summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers.go7
-rw-r--r--pkg/api/handlers/compat/images.go12
-rw-r--r--pkg/api/handlers/compat/images_build.go6
-rw-r--r--pkg/api/handlers/utils/containers.go35
-rw-r--r--pkg/bindings/images/build.go2
-rw-r--r--pkg/specgen/generate/kube/kube.go4
-rw-r--r--pkg/systemd/generate/common.go23
-rw-r--r--pkg/systemd/generate/containers.go31
-rw-r--r--pkg/systemd/generate/containers_test.go46
9 files changed, 142 insertions, 24 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 263d64a7b..6bc02dd2b 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -379,6 +379,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
if err != nil {
return nil, err
}
+ // Docker uses UTC
+ if inspect != nil && inspect.State != nil {
+ inspect.State.StartedAt = inspect.State.StartedAt.UTC()
+ inspect.State.FinishedAt = inspect.State.FinishedAt.UTC()
+ }
i, err := json.Marshal(inspect.State)
if err != nil {
return nil, err
@@ -425,7 +430,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
cb := types.ContainerJSONBase{
ID: l.ID(),
- Created: l.CreatedTime().Format(time.RFC3339Nano),
+ Created: l.CreatedTime().UTC().Format(time.RFC3339Nano), // Docker uses UTC
Path: inspect.Path,
Args: inspect.Args,
State: &state,
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 4b7a2a71c..3f4320efa 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -324,7 +324,11 @@ loop: // break out of for/select infinite loop
flush()
case <-runCtx.Done():
if !failed {
- report.Status = "Pull complete"
+ if utils.IsLibpodRequest(r) {
+ report.Status = "Pull complete"
+ } else {
+ report.Status = "Download complete"
+ }
report.Id = img[0:12]
if err := enc.Encode(report); err != nil {
logrus.Warnf("Failed to json encode error %q", err.Error())
@@ -455,10 +459,6 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, fmt.Errorf("no images to download"))
return
}
- if len(query.Names) > 1 {
- utils.Error(w, "Something went wrong.", http.StatusNotImplemented, fmt.Errorf("getting multiple image is not supported yet"))
- return
- }
images := query.Names
tmpfile, err := ioutil.TempFile("", "api.tar")
@@ -474,7 +474,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
imageEngine := abi.ImageEngine{Libpod: runtime}
- saveOptions := entities.ImageSaveOptions{Format: "docker-archive", Output: tmpfile.Name()}
+ saveOptions := entities.ImageSaveOptions{Format: "docker-archive", Output: tmpfile.Name(), MultiImageArchive: true}
if err := imageEngine.Save(r.Context(), images[0], images[1:], saveOptions); err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index ec40fdd2d..6ff557291 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -24,7 +24,7 @@ import (
"github.com/containers/podman/v3/pkg/channel"
"github.com/containers/storage/pkg/archive"
"github.com/gorilla/schema"
- specs "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -553,6 +553,10 @@ loop:
}
}
break loop
+ case <-r.Context().Done():
+ cancel()
+ logrus.Infof("Client disconnect reported for build %q / %q.", registry, query.Dockerfile)
+ return
}
}
}
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index c4c9cc2ea..6c708f74e 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -7,6 +7,7 @@ import (
"strconv"
"time"
+ "github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
@@ -175,7 +176,7 @@ func waitDockerCondition(ctx context.Context, containerName string, interval tim
var code int32
switch dockerCondition {
case "next-exit":
- code, err = waitNextExit(containerWait)
+ code, err = waitNextExit(ctx, containerName)
case "removed":
code, err = waitRemoved(containerWait)
case "not-running", "":
@@ -202,12 +203,32 @@ func waitRemoved(ctrWait containerWaitFn) (int32, error) {
return code, err
}
-func waitNextExit(ctrWait containerWaitFn) (int32, error) {
- _, err := ctrWait(define.ContainerStateRunning)
- if err != nil {
- return -1, err
- }
- return ctrWait(notRunningStates...)
+func waitNextExit(ctx context.Context, containerName string) (int32, error) {
+ runtime := ctx.Value("runtime").(*libpod.Runtime)
+ containerEngine := &abi.ContainerEngine{Libpod: runtime}
+ eventChannel := make(chan *events.Event)
+ errChannel := make(chan error)
+ opts := entities.EventsOptions{
+ EventChan: eventChannel,
+ Filter: []string{"event=died", fmt.Sprintf("container=%s", containerName)},
+ Stream: true,
+ }
+
+ // ctx is used to cancel event watching goroutine
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ go func() {
+ errChannel <- containerEngine.Events(ctx, opts)
+ }()
+
+ evt, ok := <-eventChannel
+ if ok {
+ return int32(evt.ContainerExitCode), nil
+ }
+ // if ok == false then containerEngine.Events() has exited
+ // it may happen if request was canceled (e.g. client closed connection prematurely) or
+ // the server is in process of shutting down
+ return -1, <-errChannel
}
func waitNotRunning(ctrWait containerWaitFn) (int32, error) {
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index 6acfcc1c8..f5e7c0c98 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -127,6 +127,8 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
}
if options.RemoveIntermediateCtrs {
params.Set("rm", "1")
+ } else {
+ params.Set("rm", "0")
}
if len(options.From) > 0 {
params.Set("from", options.From)
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index ccce3edba..4e41061a5 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -23,6 +23,10 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
p := specgen.NewPodSpecGenerator()
p.Name = podName
p.Labels = podYAML.ObjectMeta.Labels
+ // Kube pods must share {ipc, net, uts} by default
+ p.SharedNamespaces = append(p.SharedNamespaces, "ipc")
+ p.SharedNamespaces = append(p.SharedNamespaces, "net")
+ p.SharedNamespaces = append(p.SharedNamespaces, "uts")
// TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID}
// which is not currently possible with pod create
if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace {
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index eafd45528..0f667e2f4 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -89,19 +89,24 @@ func filterCommonContainerFlags(command []string, argCount int) []string {
// see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines
func escapeSystemdArguments(command []string) []string {
for i := range command {
- command[i] = strings.ReplaceAll(command[i], "$", "$$")
- command[i] = strings.ReplaceAll(command[i], "%", "%%")
- if strings.ContainsAny(command[i], " \t") {
- command[i] = strconv.Quote(command[i])
- } else if strings.Contains(command[i], `\`) {
- // strconv.Quote also escapes backslashes so
- // we should replace only if strconv.Quote was not used
- command[i] = strings.ReplaceAll(command[i], `\`, `\\`)
- }
+ command[i] = escapeSystemdArg(command[i])
}
return command
}
+func escapeSystemdArg(arg string) string {
+ arg = strings.ReplaceAll(arg, "$", "$$")
+ arg = strings.ReplaceAll(arg, "%", "%%")
+ if strings.ContainsAny(arg, " \t") {
+ arg = strconv.Quote(arg)
+ } else if strings.Contains(arg, `\`) {
+ // strconv.Quote also escapes backslashes so
+ // we should replace only if strconv.Quote was not used
+ arg = strings.ReplaceAll(arg, `\`, `\\`)
+ }
+ return arg
+}
+
func removeDetachArg(args []string, argCount int) []string {
// "--detach=false" could also be in the container entrypoint
// split them off so we do not remove it there
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index e06655a8d..eb1fb67ff 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -54,6 +54,12 @@ type containerInfo struct {
// CreateCommand is the full command plus arguments of the process the
// container has been created with.
CreateCommand []string
+ // containerEnv stores the container environment variables
+ containerEnv []string
+ // ExtraEnvs contains the container environment variables referenced
+ // by only the key in the container create command, e.g. --env FOO.
+ // This is only used with --new
+ ExtraEnvs []string
// EnvVariable is generate.EnvVariable and must not be set.
EnvVariable string
// ExecStartPre of the unit.
@@ -87,6 +93,9 @@ After={{{{- range $index, $value := .BoundToServices -}}}}{{{{if $index}}}} {{{{
[Service]
Environment={{{{.EnvVariable}}}}=%n
+{{{{- if .ExtraEnvs}}}}
+Environment={{{{- range $index, $value := .ExtraEnvs -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}{{{{end}}}}
+{{{{- end}}}}
Restart={{{{.RestartPolicy}}}}
TimeoutStopSec={{{{.TimeoutStopSec}}}}
{{{{- if .ExecStartPre}}}}
@@ -153,6 +162,8 @@ func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSyste
return nil, errors.Errorf("could not lookup container's runroot: got empty string")
}
+ envs := config.Spec.Process.Env
+
info := containerInfo{
ServiceName: serviceName,
ContainerNameOrID: nameOrID,
@@ -163,6 +174,7 @@ func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSyste
CreateCommand: createCommand,
GraphRoot: graphRoot,
RunRoot: runRoot,
+ containerEnv: envs,
}
return &info, nil
@@ -248,6 +260,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
fs.BoolP("detach", "d", false, "")
fs.String("name", "", "")
fs.Bool("replace", false, "")
+ fs.StringArrayP("env", "e", nil, "")
fs.Parse(remainingCmd)
remainingCmd = filterCommonContainerFlags(remainingCmd, fs.NArg())
@@ -304,6 +317,24 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
remainingCmd = removeReplaceArg(remainingCmd, fs.NArg())
}
}
+
+ envs, err := fs.GetStringArray("env")
+ if err != nil {
+ return "", err
+ }
+ for _, env := range envs {
+ // if env arg does not contain a equal sign we have to add the envar to the unit
+ // because it does try to red the value from the environment
+ if !strings.Contains(env, "=") {
+ for _, containerEnv := range info.containerEnv {
+ split := strings.SplitN(containerEnv, "=", 2)
+ if split[0] == env {
+ info.ExtraEnvs = append(info.ExtraEnvs, escapeSystemdArg(containerEnv))
+ }
+ }
+ }
+ }
+
startCommand = append(startCommand, remainingCmd...)
startCommand = escapeSystemdArguments(startCommand)
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index 899ba6bfa..75b08526b 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -445,6 +445,32 @@ Type=forking
[Install]
WantedBy=multi-user.target default.target
`
+
+ goodNewWithEnvar := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+RequiresMountsFor=/var/lib/containers/storage /var/run/containers/storage
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Environment=FOO=abc "BAR=my test" USER=%%a
+Restart=always
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --env FOO --env=BAR --env=MYENV=2 -e USER awesome-image:latest
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
tests := []struct {
name string
info containerInfo
@@ -873,6 +899,26 @@ WantedBy=multi-user.target default.target
false,
false,
},
+ {"good with environment variables",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ GraphRoot: "/var/lib/containers/storage",
+ RunRoot: "/var/run/containers/storage",
+ CreateCommand: []string{"I'll get stripped", "create", "--env", "FOO", "--env=BAR", "--env=MYENV=2", "-e", "USER", "awesome-image:latest"},
+ containerEnv: []string{"FOO=abc", "BAR=my test", "USER=%a", "MYENV=2"},
+ EnvVariable: define.EnvVariable,
+ },
+ goodNewWithEnvar,
+ true,
+ false,
+ false,
+ },
}
for _, tt := range tests {
test := tt