New upstream version 0.14.10+ds1
Reinhard Tartler
3 years ago
309 | 309 | changed, a lock renumbering must be performed, using the |
310 | 310 | `podman system renumber` command. |
311 | 311 | |
312 | **active_service**="" | |
313 | Name of destination for accessing the Podman service. | |
314 | ||
315 | **[service_destinations]** | |
316 | ||
317 | **[service_destinations.{name}]** | |
318 | **uri="ssh://user@production.example.com/run/user/1001/podman/podman.sock"** | |
319 | ||
320 | Example URIs: | |
321 | ||
322 | - **rootless local** - unix://run/user/1000/podman/podman.sock | |
323 | - **rootless remote** - ssh://user@engineering.lab.company.com/run/user/1000/podman/podman.sock | |
324 | - **rootfull local** - unix://run/podman/podman.sock | |
325 | - **rootfull remote** - ssh://root@10.10.1.136:22/run/podman/podman.sock | |
326 | ||
327 | **identity="~/.ssh/id_rsa** | |
328 | Path to file containing ssh identity key | |
329 | ||
312 | 330 | **pull_policy**="always"|"missing"|"never" |
313 | 331 | Pull image before running or creating a container. The default is **missing**. |
314 | 332 |
56 | 56 | return capabilityList |
57 | 57 | } |
58 | 58 | |
59 | // normalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet | |
59 | // NormalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet | |
60 | 60 | // present). |
61 | func normalizeCapabilities(caps []string) ([]string, error) { | |
61 | func NormalizeCapabilities(caps []string) ([]string, error) { | |
62 | 62 | normalized := make([]string, len(caps)) |
63 | 63 | for i, c := range caps { |
64 | 64 | c = strings.ToUpper(c) |
97 | 97 | var caps []string |
98 | 98 | |
99 | 99 | // Normalize the base capabilities |
100 | base, err := normalizeCapabilities(base) | |
100 | base, err := NormalizeCapabilities(base) | |
101 | 101 | if err != nil { |
102 | 102 | return nil, err |
103 | 103 | } |
105 | 105 | // Nothing to tweak; we're done |
106 | 106 | return base, nil |
107 | 107 | } |
108 | capDrop, err := normalizeCapabilities(drops) | |
108 | capDrop, err := NormalizeCapabilities(drops) | |
109 | 109 | if err != nil { |
110 | 110 | return nil, err |
111 | 111 | } |
112 | capAdd, err := normalizeCapabilities(adds) | |
112 | capAdd, err := NormalizeCapabilities(adds) | |
113 | 113 | if err != nil { |
114 | 114 | return nil, err |
115 | 115 | } |
59 | 59 | |
60 | 60 | func TestNormalizeCapabilities(t *testing.T) { |
61 | 61 | strSlice := []string{"SYS_ADMIN", "net_admin", "CAP_CHOWN"} |
62 | caps, err := normalizeCapabilities(strSlice) | |
62 | caps, err := NormalizeCapabilities(strSlice) | |
63 | 63 | require.Nil(t, err) |
64 | 64 | err = ValidateCapabilities(caps) |
65 | 65 | require.Nil(t, err) |
66 | 66 | strSlice = []string{"no_ADMIN", "net_admin", "CAP_CHMOD"} |
67 | _, err = normalizeCapabilities(strSlice) | |
67 | _, err = NormalizeCapabilities(strSlice) | |
68 | 68 | assert.Error(t, err) |
69 | 69 | } |
70 | 70 |
194 | 194 | // The first path pointing to a valid file will be used. |
195 | 195 | ConmonPath []string `toml:"conmon_path,omitempty"` |
196 | 196 | |
197 | //DetachKeys is the sequence of keys used to detach a container. | |
197 | // DetachKeys is the sequence of keys used to detach a container. | |
198 | 198 | DetachKeys string `toml:"detach_keys,omitempty"` |
199 | 199 | |
200 | 200 | // EnablePortReservation determines whether engine will reserve ports on the |
265 | 265 | // Indicates whether the application should be running in Remote mode |
266 | 266 | Remote bool `toml:"-"` |
267 | 267 | |
268 | // RemoteURI is deprecated, see ActiveService | |
268 | 269 | // RemoteURI containers connection information used to connect to remote system. |
269 | 270 | RemoteURI string `toml:"remote_uri,omitempty"` |
270 | 271 | |
271 | // Identity key file for RemoteURI | |
272 | // RemoteIdentity is deprecated, ServiceDestinations | |
273 | // RemoteIdentity key file for RemoteURI | |
272 | 274 | RemoteIdentity string `toml:"remote_identity,omitempty"` |
275 | ||
276 | // ActiveService index to Destinations added v2.0.3 | |
277 | ActiveService string `toml:"active_service,omitempty"` | |
278 | ||
279 | // Destinations mapped by service Names | |
280 | ServiceDestinations map[string]Destination `toml:"service_destinations,omitempty"` | |
273 | 281 | |
274 | 282 | // RuntimePath is the path to OCI runtime binary for launching containers. |
275 | 283 | // The first path pointing to a valid file will be used This is used only |
384 | 392 | |
385 | 393 | // NetworkConfigDir is where CNI network configuration files are stored. |
386 | 394 | NetworkConfigDir string `toml:"network_config_dir,omitempty"` |
395 | } | |
396 | ||
397 | // Destination represents destination for remote service | |
398 | type Destination struct { | |
399 | // URI, required. Example: ssh://root@example.com:22/run/podman/podman.sock | |
400 | URI string `toml:"uri"` | |
401 | ||
402 | // Identity file with ssh key, optional | |
403 | Identity string `toml:"identity,omitempty"` | |
387 | 404 | } |
388 | 405 | |
389 | 406 | // NewConfig creates a new Config. It starts with an empty config and, if |
856 | 873 | return OverrideContainersConfig |
857 | 874 | } |
858 | 875 | |
859 | func customConfigFile() (string, error) { | |
860 | path := os.Getenv("CONTAINERS_CONF") | |
861 | if path != "" { | |
862 | return path, nil | |
863 | } | |
864 | if unshare.IsRootless() { | |
865 | path, err := rootlessConfigPath() | |
866 | if err != nil { | |
867 | return "", err | |
868 | } | |
869 | return path, nil | |
870 | } | |
871 | return OverrideContainersConfig, nil | |
872 | } | |
873 | ||
874 | //ReadCustomConfig reads the custom config and only generates a config based on it | |
875 | //If the custom config file does not exists, function will return an empty config | |
876 | // ReadCustomConfig reads the custom config and only generates a config based on it | |
877 | // If the custom config file does not exists, function will return an empty config | |
876 | 878 | func ReadCustomConfig() (*Config, error) { |
877 | 879 | path, err := customConfigFile() |
878 | 880 | if err != nil { |
929 | 931 | } |
930 | 932 | return nil |
931 | 933 | } |
934 | ||
935 | // Reload reloads the configuration from containers.conf files | |
936 | func Reload() (*Config, error) { | |
937 | var err error | |
938 | config, err = NewConfig("") | |
939 | if err != nil { | |
940 | return nil, errors.Wrapf(err, "containers.conf reload failed") | |
941 | } | |
942 | return Default() | |
943 | } | |
944 | ||
945 | func (c *Config) ActiveDestination() (string, string, error){ | |
946 | if uri, found := os.LookupEnv("CONTAINER_HOST"); found { | |
947 | var ident string | |
948 | if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found { | |
949 | ident = v | |
950 | } | |
951 | return uri, ident, nil | |
952 | } | |
953 | ||
954 | switch { | |
955 | case c.Engine.ActiveService != "": | |
956 | d, found := c.Engine.ServiceDestinations[c.Engine.ActiveService] | |
957 | if !found { | |
958 | return "", "", errors.Errorf("%q service destination not found", c.Engine.ActiveService) | |
959 | } | |
960 | return d.URI, d.Identity, nil | |
961 | case c.Engine.RemoteURI != "": | |
962 | return c.Engine.RemoteURI, c.Engine.RemoteIdentity, nil | |
963 | } | |
964 | return "", "", errors.New("no service destination configured") | |
965 | } |
0 | package config | |
1 | ||
2 | import ( | |
3 | "os" | |
4 | ) | |
5 | ||
6 | func customConfigFile() (string, error) { | |
7 | if path, found := os.LookupEnv("CONTAINERS_CONF"); found { | |
8 | return path, nil | |
9 | } | |
10 | return rootlessConfigPath() | |
11 | } |
0 | 0 | package config |
1 | 1 | |
2 | import selinux "github.com/opencontainers/selinux/go-selinux" | |
2 | import ( | |
3 | "os" | |
4 | ||
5 | "github.com/containers/storage/pkg/unshare" | |
6 | selinux "github.com/opencontainers/selinux/go-selinux" | |
7 | ) | |
3 | 8 | |
4 | 9 | func selinuxEnabled() bool { |
5 | 10 | return selinux.GetEnabled() |
6 | 11 | } |
12 | ||
13 | func customConfigFile() (string, error) { | |
14 | if path, found := os.LookupEnv("CONTAINERS_CONF"); found { | |
15 | return path, nil | |
16 | } | |
17 | if unshare.IsRootless() { | |
18 | path, err := rootlessConfigPath() | |
19 | if err != nil { | |
20 | return "", err | |
21 | } | |
22 | return path, nil | |
23 | } | |
24 | return OverrideContainersConfig, nil | |
25 | } |
5 | 5 | "io/ioutil" |
6 | 6 | "os" |
7 | 7 | "path" |
8 | "strings" | |
8 | 9 | |
9 | 10 | . "github.com/onsi/ginkgo" |
10 | 11 | "github.com/onsi/gomega" |
173 | 174 | // Then |
174 | 175 | gomega.Expect(err).To(gomega.BeNil()) |
175 | 176 | gomega.Expect(config.Engine.Remote).To(gomega.BeFalse()) |
177 | }) | |
178 | ||
179 | It("verify getDefaultEnv", func() { | |
180 | envs := []string{ | |
181 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", | |
182 | "TERM=xterm", | |
183 | } | |
184 | ||
185 | // When | |
186 | config, err := Default() | |
187 | // Then | |
188 | gomega.Expect(err).To(gomega.BeNil()) | |
189 | gomega.Expect(config.GetDefaultEnv()).To(gomega.BeEquivalentTo(envs)) | |
190 | config.Containers.HTTPProxy = true | |
191 | gomega.Expect(config.GetDefaultEnv()).To(gomega.BeEquivalentTo(envs)) | |
192 | os.Setenv("HTTP_PROXY", "localhost") | |
193 | os.Setenv("FOO", "BAR") | |
194 | newenvs := []string{"HTTP_PROXY=localhost"} | |
195 | envs = append(newenvs, envs...) | |
196 | gomega.Expect(config.GetDefaultEnv()).To(gomega.BeEquivalentTo(envs)) | |
197 | config.Containers.HTTPProxy = false | |
198 | config.Containers.EnvHost = true | |
199 | envString := strings.Join(config.GetDefaultEnv(), ",") | |
200 | gomega.Expect(envString).To(gomega.ContainSubstring("FOO=BAR")) | |
201 | gomega.Expect(envString).To(gomega.ContainSubstring("HTTP_PROXY=localhost")) | |
176 | 202 | }) |
177 | 203 | |
178 | 204 | It("write", func() { |
2 | 2 | import ( |
3 | 3 | "os" |
4 | 4 | "sort" |
5 | "strings" | |
6 | 5 | |
7 | 6 | "github.com/containers/common/pkg/apparmor" |
8 | 7 | "github.com/containers/common/pkg/capabilities" |
152 | 151 | |
153 | 152 | envs := []string{ |
154 | 153 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
154 | "TERM=xterm", | |
155 | 155 | } |
156 | 156 | |
157 | 157 | // Then |
229 | 229 | |
230 | 230 | envs := []string{ |
231 | 231 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
232 | "TERM=xterm", | |
232 | 233 | } |
233 | 234 | |
234 | 235 | // When |
243 | 244 | gomega.Expect(config.Engine.OCIRuntimes["runc"]).To(gomega.Equal(OCIRuntimeMap["runc"])) |
244 | 245 | }) |
245 | 246 | |
246 | It("verify getDefaultEnv", func() { | |
247 | envs := []string{ | |
248 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", | |
249 | } | |
250 | ||
251 | // When | |
252 | config, err := Default() | |
253 | // Then | |
254 | gomega.Expect(err).To(gomega.BeNil()) | |
255 | gomega.Expect(config.GetDefaultEnv()).To(gomega.BeEquivalentTo(envs)) | |
256 | config.Containers.HTTPProxy = true | |
257 | gomega.Expect(config.GetDefaultEnv()).To(gomega.BeEquivalentTo(envs)) | |
258 | os.Setenv("HTTP_PROXY", "localhost") | |
259 | os.Setenv("FOO", "BAR") | |
260 | newenvs := []string{"HTTP_PROXY=localhost"} | |
261 | envs = append(newenvs, envs...) | |
262 | gomega.Expect(config.GetDefaultEnv()).To(gomega.BeEquivalentTo(envs)) | |
263 | config.Containers.HTTPProxy = false | |
264 | config.Containers.EnvHost = true | |
265 | envString := strings.Join(config.GetDefaultEnv(), ",") | |
266 | gomega.Expect(envString).To(gomega.ContainSubstring("FOO=BAR")) | |
267 | gomega.Expect(envString).To(gomega.ContainSubstring("HTTP_PROXY=localhost")) | |
268 | }) | |
269 | ||
270 | 247 | It("should success with valid user file path", func() { |
271 | 248 | // Given |
272 | 249 | // When |
0 | package config | |
1 | ||
2 | import "os" | |
3 | ||
4 | func customConfigFile() (string, error) { | |
5 | if path, found := os.LookupEnv("CONTAINERS_CONF"); found { | |
6 | return path, nil | |
7 | } | |
8 | return os.Getenv("APPDATA") + "\\containers\\containers.conf", nil | |
9 | } |
115 | 115 | # |
116 | 116 | # env = [ |
117 | 117 | # "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
118 | # "TERM=xterm", | |
118 | 119 | # ] |
119 | 120 | |
120 | 121 | # Pass all host environment variables into the container. |
365 | 366 | |
366 | 367 | # Number of seconds to wait for container to exit before sending kill signal. |
367 | 368 | # stop_timeout = 10 |
369 | ||
370 | # Index to the active service | |
371 | # active_service = production | |
372 | ||
373 | # map of service destinations | |
374 | # [service_destinations] | |
375 | # [service_destinations.production] | |
376 | # URI to access the Podman service | |
377 | # Examples: | |
378 | # rootless "unix://run/user/$UID/podman/podman.sock" (Default) | |
379 | # rootfull "unix://run/podman/podman.sock (Default) | |
380 | # remote rootless ssh://engineering.lab.company.com/run/user/1000/podman/podman.sock | |
381 | # remote rootfull ssh://root@10.10.1.136:22/run/podman/podman.sock | |
382 | # uri="ssh://user@production.example.com/run/user/1001/podman/podman.sock" | |
383 | # Path to file containing ssh identity key | |
384 | # identity = "~/.ssh/id_rsa" | |
368 | 385 | |
369 | 386 | # Paths to look for a valid OCI runtime (runc, runv, kata, etc) |
370 | 387 | [engine.runtimes] |
175 | 175 | EnableLabeling: selinuxEnabled(), |
176 | 176 | Env: []string{ |
177 | 177 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
178 | "TERM=xterm", | |
178 | 179 | }, |
179 | 180 | EnvHost: false, |
180 | 181 | HTTPProxy: false, |
17 | 17 | # environment variables to conmon or the runtime. |
18 | 18 | # env = [ |
19 | 19 | # "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
20 | # "TERM=xterm", | |
20 | 21 | # ] |
21 | 22 | |
22 | 23 | # proxy environment variables are passed into the container |
55 | 55 | # environment variables to conmon or the runtime. |
56 | 56 | env = [ |
57 | 57 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
58 | "TERM=xterm", | |
58 | 59 | ] |
59 | 60 | |
60 | 61 | # Path to OCI hooks directories for automatically executed hooks. |