summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers.go3
-rw-r--r--pkg/api/handlers/compat/containers_create.go2
-rw-r--r--pkg/api/handlers/compat/containers_logs.go21
-rw-r--r--pkg/api/handlers/compat/containers_stats.go43
-rw-r--r--pkg/api/handlers/libpod/containers_stats.go72
-rw-r--r--pkg/api/handlers/libpod/images_pull.go9
-rw-r--r--pkg/api/handlers/types.go2
-rw-r--r--pkg/api/server/handler_api.go17
-rw-r--r--pkg/api/server/register_containers.go31
-rw-r--r--pkg/bindings/bindings.go2
-rw-r--r--pkg/bindings/containers/containers.go51
-rw-r--r--pkg/bindings/images/pull.go1
-rw-r--r--pkg/bindings/system/system.go10
-rw-r--r--pkg/bindings/test/images_test.go8
-rw-r--r--pkg/domain/entities/containers.go19
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/entities/images.go2
-rw-r--r--pkg/domain/infra/abi/containers.go116
-rw-r--r--pkg/domain/infra/abi/images.go9
-rw-r--r--pkg/domain/infra/abi/play.go13
-rw-r--r--pkg/domain/infra/abi/system_varlink.go2
-rw-r--r--pkg/domain/infra/abi/terminal/terminal.go2
-rw-r--r--pkg/domain/infra/tunnel/containers.go108
-rw-r--r--pkg/domain/infra/tunnel/events.go32
-rw-r--r--pkg/domain/infra/tunnel/helpers.go4
-rw-r--r--pkg/domain/infra/tunnel/images.go24
-rw-r--r--pkg/hooks/1.0.0/hook.go9
-rw-r--r--pkg/hooks/hooks.go6
-rw-r--r--pkg/specgen/generate/storage.go4
-rw-r--r--pkg/systemd/generate/containers.go2
-rw-r--r--pkg/systemd/generate/pods.go2
-rw-r--r--pkg/varlinkapi/system.go8
32 files changed, 506 insertions, 130 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index f9e200ff3..3a904ba87 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -103,7 +103,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- if _, found := r.URL.Query()["limit"]; found && query.Limit != -1 {
+ if _, found := r.URL.Query()["limit"]; found && query.Limit > 0 {
last := query.Limit
if len(containers) > last {
containers = containers[len(containers)-last:]
@@ -193,6 +193,7 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
err = con.Kill(signal)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name))
+ return
}
// Docker waits for the container to stop if the signal is 0 or
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 93e4fe540..1d0b4c45d 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -210,7 +210,7 @@ func makeCreateConfig(ctx context.Context, containerConfig *config.Config, input
ImageID: newImage.ID(),
BuiltinImgVolumes: nil, // podman
ImageVolumeType: "", // podman
- Interactive: false,
+ Interactive: input.OpenStdin,
// IpcMode: input.HostConfig.IpcMode,
Labels: input.Labels,
LogDriver: input.HostConfig.LogConfig.Type, // is this correct
diff --git a/pkg/api/handlers/compat/containers_logs.go b/pkg/api/handlers/compat/containers_logs.go
index f6d4a518e..d24b7d959 100644
--- a/pkg/api/handlers/compat/containers_logs.go
+++ b/pkg/api/handlers/compat/containers_logs.go
@@ -105,6 +105,18 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
var frame strings.Builder
header := make([]byte, 8)
+
+ writeHeader := true
+ // Docker does not write stream headers iff the container has a tty.
+ if !utils.IsLibpodRequest(r) {
+ inspectData, err := ctnr.Inspect(false)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain logs for Container '%s'", name))
+ return
+ }
+ writeHeader = !inspectData.Config.Tty
+ }
+
for line := range logChannel {
if _, found := r.URL.Query()["until"]; found {
if line.Time.After(until) {
@@ -138,10 +150,13 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
}
frame.WriteString(line.Msg)
- binary.BigEndian.PutUint32(header[4:], uint32(frame.Len()))
- if _, err := w.Write(header[0:8]); err != nil {
- log.Errorf("unable to write log output header: %q", err)
+ if writeHeader {
+ binary.BigEndian.PutUint32(header[4:], uint32(frame.Len()))
+ if _, err := w.Write(header[0:8]); err != nil {
+ log.Errorf("unable to write log output header: %q", err)
+ }
}
+
if _, err := io.WriteString(w, frame.String()); err != nil {
log.Errorf("unable to write frame string: %q", err)
}
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go
index 3d7d49ad3..16bd0518a 100644
--- a/pkg/api/handlers/compat/containers_stats.go
+++ b/pkg/api/handlers/compat/containers_stats.go
@@ -75,32 +75,48 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
}
}
- for ok := true; ok; ok = query.Stream {
+ // Write header and content type.
+ w.WriteHeader(http.StatusOK)
+ w.Header().Add("Content-Type", "application/json")
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+
+ // Setup JSON encoder for streaming.
+ coder := json.NewEncoder(w)
+ coder.SetEscapeHTML(true)
+
+streamLabel: // A label to flatten the scope
+ select {
+ case <-r.Context().Done():
+ logrus.Debugf("Client connection (container stats) cancelled")
+
+ default:
// Container stats
stats, err := ctnr.GetContainerStats(stats)
if err != nil {
- utils.InternalServerError(w, err)
+ logrus.Errorf("Unable to get container stats: %v", err)
return
}
inspect, err := ctnr.Inspect(false)
if err != nil {
- utils.InternalServerError(w, err)
+ logrus.Errorf("Unable to inspect container: %v", err)
return
}
// Cgroup stats
cgroupPath, err := ctnr.CGroupPath()
if err != nil {
- utils.InternalServerError(w, err)
+ logrus.Errorf("Unable to get cgroup path of container: %v", err)
return
}
cgroup, err := cgroups.Load(cgroupPath)
if err != nil {
- utils.InternalServerError(w, err)
+ logrus.Errorf("Unable to load cgroup: %v", err)
return
}
cgroupStat, err := cgroup.Stat()
if err != nil {
- utils.InternalServerError(w, err)
+ logrus.Errorf("Unable to get cgroup stats: %v", err)
return
}
@@ -175,11 +191,18 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
Networks: net,
}
- utils.WriteJSON(w, http.StatusOK, s)
+ if err := coder.Encode(s); err != nil {
+ logrus.Errorf("Unable to encode stats: %v", err)
+ return
+ }
if flusher, ok := w.(http.Flusher); ok {
flusher.Flush()
}
+ if !query.Stream {
+ return
+ }
+
preRead = s.Read
bits, err := json.Marshal(s.CPUStats)
if err != nil {
@@ -189,10 +212,8 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
logrus.Errorf("Unable to unmarshal previous stats: %q", err)
}
- // Only sleep when we're streaming.
- if query.Stream {
- time.Sleep(DefaultStatsPeriod)
- }
+ time.Sleep(DefaultStatsPeriod)
+ goto streamLabel
}
}
diff --git a/pkg/api/handlers/libpod/containers_stats.go b/pkg/api/handlers/libpod/containers_stats.go
new file mode 100644
index 000000000..4d5abe118
--- /dev/null
+++ b/pkg/api/handlers/libpod/containers_stats.go
@@ -0,0 +1,72 @@
+package libpod
+
+import (
+ "encoding/json"
+ "net/http"
+ "time"
+
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+const DefaultStatsPeriod = 5 * time.Second
+
+func StatsContainer(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+
+ query := struct {
+ Containers []string `schema:"containers"`
+ Stream bool `schema:"stream"`
+ }{
+ Stream: true,
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ // Reduce code duplication and use the local/abi implementation of
+ // container stats.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
+ statsOptions := entities.ContainerStatsOptions{
+ Stream: query.Stream,
+ }
+
+ // Stats will stop if the connection is closed.
+ statsChan, err := containerEngine.ContainerStats(r.Context(), query.Containers, statsOptions)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+
+ // Write header and content type.
+ w.WriteHeader(http.StatusOK)
+ w.Header().Add("Content-Type", "application/json")
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+
+ // Setup JSON encoder for streaming.
+ coder := json.NewEncoder(w)
+ coder.SetEscapeHTML(true)
+
+ for stats := range statsChan {
+ if err := coder.Encode(stats); err != nil {
+ // Note: even when streaming, the stats goroutine will
+ // be notified (and stop) as the connection will be
+ // closed.
+ logrus.Errorf("Unable to encode stats: %v", err)
+ return
+ }
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+ }
+}
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index 8a2f4f4cf..ad8d1f38e 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -178,10 +178,19 @@ loop: // break out of for/select infinite loop
flush()
case <-runCtx.Done():
if !failed {
+ // Send all image id's pulled in 'images' stanza
report.Images = images
if err := enc.Encode(report); err != nil {
logrus.Warnf("Failed to json encode error %q", err.Error())
}
+
+ report.Images = nil
+ // Pull last ID from list and publish in 'id' stanza. This maintains previous API contract
+ report.ID = images[len(images)-1]
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+
flush()
}
break loop // break out of for/select infinite loop
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 0ccaa95bb..9e503dbb0 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -33,7 +33,7 @@ type LibpodImagesLoadReport struct {
}
type LibpodImagesPullReport struct {
- ID string `json:"id"`
+ entities.ImagePullReport
}
// LibpodImagesRemoveReport is the return type for image removal via the rest
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index f2ce0301b..920811c51 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -34,15 +34,18 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
}
// TODO: Use r.ConnContext when ported to go 1.13
- c := context.WithValue(r.Context(), "decoder", s.Decoder) //nolint
- c = context.WithValue(c, "runtime", s.Runtime) //nolint
- c = context.WithValue(c, "shutdownFunc", s.Shutdown) //nolint
- c = context.WithValue(c, "idletracker", s.idleTracker) //nolint
+ c := context.WithValue(r.Context(), "decoder", s.Decoder) // nolint
+ c = context.WithValue(c, "runtime", s.Runtime) // nolint
+ c = context.WithValue(c, "shutdownFunc", s.Shutdown) // nolint
+ c = context.WithValue(c, "idletracker", s.idleTracker) // nolint
r = r.WithContext(c)
- v := utils.APIVersion[utils.CompatTree][utils.CurrentAPIVersion]
- w.Header().Set("API-Version", fmt.Sprintf("%d.%d", v.Major, v.Minor))
- w.Header().Set("Libpod-API-Version", utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String())
+ cv := utils.APIVersion[utils.CompatTree][utils.CurrentAPIVersion]
+ w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor))
+
+ lv := utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String()
+ w.Header().Set("Libpod-API-Version", lv)
+ w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
h(w, r)
}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 0ad5d29ea..870c6a90c 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -1013,7 +1013,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// tags:
// - containers
// summary: Get stats for a container
- // description: This returns a live stream of a container’s resource usage statistics.
+ // description: DEPRECATED. This endpoint will be removed with the next major release. Please use /libpod/containers/stats instead.
// parameters:
// - in: path
// name: name
@@ -1035,6 +1035,35 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/{name}/stats"), s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/containers/stats libpod libpodStatsContainers
+ // ---
+ // tags:
+ // - containers
+ // summary: Get stats for one or more containers
+ // description: Return a live stream of resource usage statistics of one or more container. If no container is specified, the statistics of all containers are returned.
+ // parameters:
+ // - in: query
+ // name: containers
+ // description: names or IDs of containers
+ // type: array
+ // items:
+ // type: string
+ // - in: query
+ // name: stream
+ // type: boolean
+ // default: true
+ // description: Stream the output
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // description: no error
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/stats"), s.APIHandler(libpod.StatsContainer)).Methods(http.MethodGet)
+
// swagger:operation GET /libpod/containers/{name}/top libpod libpodTopContainer
// ---
// tags:
diff --git a/pkg/bindings/bindings.go b/pkg/bindings/bindings.go
index ae5610b0f..14f306910 100644
--- a/pkg/bindings/bindings.go
+++ b/pkg/bindings/bindings.go
@@ -22,5 +22,5 @@ var (
PFalse = &pFalse
// APIVersion - podman will fail to run if this value is wrong
- APIVersion = semver.MustParse("1.0.0")
+ APIVersion = semver.MustParse("2.0.0")
)
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 981912665..46e4df1d2 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -197,7 +197,56 @@ func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
return response.Process(nil)
}
-func Stats() {}
+func Stats(ctx context.Context, containers []string, stream *bool) (chan entities.ContainerStatsReport, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ if stream != nil {
+ params.Set("stream", strconv.FormatBool(*stream))
+ }
+ for _, c := range containers {
+ params.Add("containers", c)
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/stats", params, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ statsChan := make(chan entities.ContainerStatsReport)
+
+ go func() {
+ defer close(statsChan)
+
+ dec := json.NewDecoder(response.Body)
+ doStream := true
+ if stream != nil {
+ doStream = *stream
+ }
+
+ streamLabel: // label to flatten the scope
+ select {
+ case <-response.Request.Context().Done():
+ return // lost connection - maybe the server quit
+ default:
+ // fall through and do some work
+ }
+ var report entities.ContainerStatsReport
+ if err := dec.Decode(&report); err != nil {
+ report = entities.ContainerStatsReport{Error: err}
+ }
+ statsChan <- report
+
+ if report.Error != nil || !doStream {
+ return
+ }
+ goto streamLabel
+ }()
+
+ return statsChan, nil
+}
// Top gathers statistics about the running processes in a container. The nameOrID can be a container name
// or a partial/full ID. The descriptors allow for specifying which data to collect from the process.
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index 261a481a2..2bfbbb2ac 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -89,6 +89,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
mErr = multierror.Append(mErr, errors.New(report.Error))
case len(report.Images) > 0:
images = report.Images
+ case report.ID != "":
default:
return images, errors.New("failed to parse pull results stream, unexpected input")
}
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
index e995770ba..1203f5c3c 100644
--- a/pkg/bindings/system/system.go
+++ b/pkg/bindings/system/system.go
@@ -118,10 +118,10 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
if err = response.Process(&component); err != nil {
return nil, err
}
- f, _ := strconv.ParseFloat(component.APIVersion, 64)
+
b, _ := time.Parse(time.RFC3339, component.BuildTime)
report.Server = &define.Version{
- APIVersion: int64(f),
+ APIVersion: component.APIVersion,
Version: component.Version.Version,
GoVersion: component.GoVersion,
GitCommit: component.GitCommit,
@@ -129,6 +129,12 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
Built: b.Unix(),
OsArch: fmt.Sprintf("%s/%s", component.Os, component.Arch),
}
+
+ for _, c := range component.Components {
+ if c.Name == "Podman Engine" {
+ report.Server.APIVersion = c.Details["APIVersion"]
+ }
+ }
return &report, err
}
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index e0dd28d7a..681855293 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -360,19 +360,19 @@ var _ = Describe("Podman images", func() {
rawImage := "docker.io/library/busybox:latest"
pulledImages, err := images.Pull(bt.conn, rawImage, entities.ImagePullOptions{})
- Expect(err).To(BeNil())
+ Expect(err).NotTo(HaveOccurred())
Expect(len(pulledImages)).To(Equal(1))
exists, err := images.Exists(bt.conn, rawImage)
- Expect(err).To(BeNil())
+ Expect(err).NotTo(HaveOccurred())
Expect(exists).To(BeTrue())
// Make sure the normalization AND the full-transport reference works.
_, err = images.Pull(bt.conn, "docker://"+rawImage, entities.ImagePullOptions{})
- Expect(err).To(BeNil())
+ Expect(err).NotTo(HaveOccurred())
// The v2 endpoint only supports the docker transport. Let's see if that's really true.
_, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", entities.ImagePullOptions{})
- Expect(err).To(Not(BeNil()))
+ Expect(err).To(HaveOccurred())
})
})
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 16997cdd1..7b272f01e 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -411,10 +411,17 @@ type ContainerCpReport struct {
// ContainerStatsOptions describes input options for getting
// stats on containers
type ContainerStatsOptions struct {
- All bool
- Format string
- Latest bool
- NoReset bool
- NoStream bool
- StatChan chan []*define.ContainerStats
+ // Operate on the latest known container. Only supported for local
+ // clients.
+ Latest bool
+ // Stream stats.
+ Stream bool
+}
+
+// ContainerStatsReport is used for streaming container stats.
+type ContainerStatsReport struct {
+ // Error from reading stats.
+ Error error
+ // Results, set when there is no error.
+ Stats []define.ContainerStats
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 6c85c9267..f105dc333 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -38,7 +38,7 @@ type ContainerEngine interface {
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
- ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) error
+ ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) (chan ContainerStatsReport, error)
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
ContainerUnmount(ctx context.Context, nameOrIDs []string, options ContainerUnmountOptions) ([]*ContainerUnmountReport, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index d0b738934..cad6693fa 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -156,6 +156,8 @@ type ImagePullReport struct {
Error string `json:"error,omitempty"`
// Images contains the ID's of the images pulled
Images []string `json:"images,omitempty"`
+ // ID contains image id (retained for backwards compatibility)
+ ID string `json:"id,omitempty"`
}
// ImagePushOptions are the arguments for pushing images.
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 21618f555..8b0d53940 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1142,12 +1142,12 @@ func (ic *ContainerEngine) Shutdown(_ context.Context) {
})
}
-func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) error {
- defer close(options.StatChan)
+func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
+ statsChan = make(chan entities.ContainerStatsReport, 1)
+
containerFunc := ic.Libpod.GetRunningContainers
+ queryAll := false
switch {
- case len(namesOrIds) > 0:
- containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
case options.Latest:
containerFunc = func() ([]*libpod.Container, error) {
lastCtr, err := ic.Libpod.GetLatestContainer()
@@ -1156,62 +1156,76 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
}
return []*libpod.Container{lastCtr}, nil
}
- case options.All:
+ case len(namesOrIds) > 0:
+ containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
+ default:
+ // No containers, no latest -> query all!
+ queryAll = true
containerFunc = ic.Libpod.GetAllContainers
}
- ctrs, err := containerFunc()
- if err != nil {
- return errors.Wrapf(err, "unable to get list of containers")
- }
- containerStats := map[string]*define.ContainerStats{}
- for _, ctr := range ctrs {
- initialStats, err := ctr.GetContainerStats(&define.ContainerStats{})
- if err != nil {
- // when doing "all", don't worry about containers that are not running
- cause := errors.Cause(err)
- if options.All && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
- continue
- }
- if cause == cgroups.ErrCgroupV1Rootless {
- err = cause
- }
- return err
+ go func() {
+ defer close(statsChan)
+ var (
+ err error
+ containers []*libpod.Container
+ containerStats map[string]*define.ContainerStats
+ )
+ containerStats = make(map[string]*define.ContainerStats)
+
+ stream: // label to flatten the scope
+ select {
+ case <-ctx.Done():
+ // client cancelled
+ logrus.Debugf("Container stats stopped: context cancelled")
+ return
+ default:
+ // just fall through and do work
}
- containerStats[ctr.ID()] = initialStats
- }
- for {
- reportStats := []*define.ContainerStats{}
- for _, ctr := range ctrs {
- id := ctr.ID()
- if _, ok := containerStats[ctr.ID()]; !ok {
- initialStats, err := ctr.GetContainerStats(&define.ContainerStats{})
- if errors.Cause(err) == define.ErrCtrRemoved || errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrStateInvalid {
- // skip dealing with a container that is gone
- continue
+
+ // Anonymous func to easily use the return values for streaming.
+ computeStats := func() ([]define.ContainerStats, error) {
+ containers, err = containerFunc()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get list of containers")
+ }
+
+ reportStats := []define.ContainerStats{}
+ for _, ctr := range containers {
+ prev, ok := containerStats[ctr.ID()]
+ if !ok {
+ prev = &define.ContainerStats{}
}
+
+ stats, err := ctr.GetContainerStats(prev)
if err != nil {
- return err
+ cause := errors.Cause(err)
+ if queryAll && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
+ continue
+ }
+ if cause == cgroups.ErrCgroupV1Rootless {
+ err = cause
+ }
+ return nil, err
}
- containerStats[id] = initialStats
- }
- stats, err := ctr.GetContainerStats(containerStats[id])
- if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
- return err
+
+ containerStats[ctr.ID()] = stats
+ reportStats = append(reportStats, *stats)
}
- // replace the previous measurement with the current one
- containerStats[id] = stats
- reportStats = append(reportStats, stats)
+ return reportStats, nil
}
- ctrs, err = containerFunc()
- if err != nil {
- return err
- }
- options.StatChan <- reportStats
- if options.NoStream {
- break
+
+ report := entities.ContainerStatsReport{}
+ report.Stats, report.Error = computeStats()
+ statsChan <- report
+
+ if report.Error != nil || !options.Stream {
+ return
}
+
time.Sleep(time.Second)
- }
- return nil
+ goto stream
+ }()
+
+ return statsChan, nil
}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index cc62c3f27..25c0c184f 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -191,6 +191,15 @@ func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options
reports := []*entities.ImageUnmountReport{}
for _, img := range images {
report := entities.ImageUnmountReport{Id: img.ID()}
+ mounted, _, err := img.Mounted()
+ if err != nil {
+ // Errors will be caught in Unmount call below
+ // Default assumption to mounted
+ mounted = true
+ }
+ if !mounted {
+ continue
+ }
if err := img.Unmount(options.Force); err != nil {
if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
logrus.Debugf("Error umounting image %s, storage.ErrLayerNotMounted", img.ID())
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 659cc799c..aa6aeede2 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -299,6 +299,18 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, err
}
+ var ctrRestartPolicy string
+ switch podYAML.Spec.RestartPolicy {
+ case v1.RestartPolicyAlways:
+ ctrRestartPolicy = libpod.RestartPolicyAlways
+ case v1.RestartPolicyOnFailure:
+ ctrRestartPolicy = libpod.RestartPolicyOnFailure
+ case v1.RestartPolicyNever:
+ ctrRestartPolicy = libpod.RestartPolicyNo
+ default: // Default to Always
+ ctrRestartPolicy = libpod.RestartPolicyAlways
+ }
+
containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
for _, container := range podYAML.Spec.Containers {
pullPolicy := util.PullImageMissing
@@ -326,6 +338,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}
+ conf.RestartPolicy = ctrRestartPolicy
ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, ic.Libpod, conf, pod)
if err != nil {
return nil, err
diff --git a/pkg/domain/infra/abi/system_varlink.go b/pkg/domain/infra/abi/system_varlink.go
index d0a5c5407..ead84fc84 100644
--- a/pkg/domain/infra/abi/system_varlink.go
+++ b/pkg/domain/infra/abi/system_varlink.go
@@ -22,7 +22,7 @@ func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.Servi
service, err := varlink.NewService(
"Atomic",
"podman",
- version.Version,
+ version.Version.String(),
"https://github.com/containers/podman",
)
if err != nil {
diff --git a/pkg/domain/infra/abi/terminal/terminal.go b/pkg/domain/infra/abi/terminal/terminal.go
index 0b6e57f49..48f5749d5 100644
--- a/pkg/domain/infra/abi/terminal/terminal.go
+++ b/pkg/domain/infra/abi/terminal/terminal.go
@@ -6,7 +6,7 @@ import (
"os/signal"
lsignal "github.com/containers/podman/v2/pkg/signal"
- "github.com/docker/docker/pkg/term"
+ "github.com/moby/term"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/client-go/tools/remotecommand"
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 35550b9be..9b03503c6 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -35,7 +35,7 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string)
}
func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
- cons, err := getContainersByContext(ic.ClientCxt, false, namesOrIds)
+ cons, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -54,7 +54,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -67,7 +67,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
}
func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -89,8 +89,8 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
id := strings.Split(string(content), "\n")[0]
namesOrIds = append(namesOrIds, id)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, options.Ignore, namesOrIds)
+ if err != nil {
return nil, err
}
for _, c := range ctrs {
@@ -120,7 +120,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -144,7 +144,7 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
timeout = &t
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -169,8 +169,8 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
id := strings.Split(string(content), "\n")[0]
namesOrIds = append(namesOrIds, id)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, options.Ignore, namesOrIds)
+ if err != nil {
return nil, err
}
// TODO there is no endpoint for container eviction. Need to discuss
@@ -283,7 +283,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
)
if options.All {
- allCtrs, err := getContainersByContext(ic.ClientCxt, true, []string{})
+ allCtrs, err := getContainersByContext(ic.ClientCxt, true, false, []string{})
if err != nil {
return nil, err
}
@@ -295,7 +295,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
}
} else {
- ctrs, err = getContainersByContext(ic.ClientCxt, false, namesOrIds)
+ ctrs, err = getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -317,7 +317,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
ctrs = []entities.ListContainer{}
)
if options.All {
- allCtrs, err := getContainersByContext(ic.ClientCxt, true, []string{})
+ allCtrs, err := getContainersByContext(ic.ClientCxt, true, false, []string{})
if err != nil {
return nil, err
}
@@ -329,7 +329,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
} else {
- ctrs, err = getContainersByContext(ic.ClientCxt, false, namesOrIds)
+ ctrs, err = getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -389,6 +389,15 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string,
}
func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
+ ctrs, err := getContainersByContext(ic.ClientCxt, false, false, []string{nameOrID})
+ if err != nil {
+ return err
+ }
+ ctr := ctrs[0]
+ if ctr.State != define.ContainerStateRunning.String() {
+ return errors.Errorf("you can only attach to running containers")
+ }
+
return containers.Attach(ic.ClientCxt, nameOrID, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr, nil)
}
@@ -472,27 +481,67 @@ func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input,
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
reports := []*entities.ContainerStartReport{}
- for _, name := range namesOrIds {
+ var exitCode = define.ExecErrorCodeGeneric
+ ctrs, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ // There can only be one container if attach was used
+ for i, ctr := range ctrs {
+ name := ctr.ID
report := entities.ContainerStartReport{
Id: name,
- RawInput: name,
- ExitCode: 125,
+ RawInput: namesOrIds[i],
+ ExitCode: exitCode,
}
+ ctrRunning := ctr.State == define.ContainerStateRunning.String()
if options.Attach {
- report.Err = startAndAttach(ic, name, &options.DetachKeys, options.Stdin, options.Stdout, options.Stderr)
- if report.Err == nil {
- exitCode, err := containers.Wait(ic.ClientCxt, name, nil)
- if err == nil {
- report.ExitCode = int(exitCode)
+ err = startAndAttach(ic, name, &options.DetachKeys, options.Stdin, options.Stdout, options.Stderr)
+ if err == define.ErrDetach {
+ // User manually detached
+ // Exit cleanly immediately
+ report.Err = err
+ reports = append(reports, &report)
+ return reports, nil
+ }
+ if ctrRunning {
+ reports = append(reports, &report)
+ return reports, nil
+ }
+
+ if err != nil {
+ report.ExitCode = define.ExitCode(report.Err)
+ report.Err = err
+ reports = append(reports, &report)
+ return reports, errors.Wrapf(report.Err, "unable to start container %s", name)
+ }
+ exitCode, err := containers.Wait(ic.ClientCxt, name, nil)
+ if err == define.ErrNoSuchCtr {
+ // Check events
+ event, err := ic.GetLastContainerEvent(ctx, name, events.Exited)
+ if err != nil {
+ logrus.Errorf("Cannot get exit code: %v", err)
+ report.ExitCode = define.ExecErrorCodeNotFound
+ } else {
+ report.ExitCode = event.ContainerExitCode
}
} else {
- report.ExitCode = define.ExitCode(report.Err)
+ report.ExitCode = int(exitCode)
}
reports = append(reports, &report)
return reports, nil
}
- report.Err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
- report.ExitCode = define.ExitCode(report.Err)
+ // Start the container if it's not running already.
+ if !ctrRunning {
+ err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
+ if err != nil {
+ report.Err = errors.Wrapf(err, "unable to start container %q", name)
+ report.ExitCode = define.ExitCode(err)
+ reports = append(reports, &report)
+ continue
+ }
+ }
+ report.ExitCode = 0
reports = append(reports, &report)
}
return reports, nil
@@ -607,7 +656,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -647,7 +696,7 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
if len(nameOrID) > 0 {
namesOrIds = append(namesOrIds, nameOrID)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -673,6 +722,9 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string,
func (ic *ContainerEngine) Shutdown(_ context.Context) {
}
-func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) error {
- return errors.New("not implemented")
+func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
+ if options.Latest {
+ return nil, errors.New("latest is not supported for the remote client")
+ }
+ return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
}
diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go
index e6f4834b9..53bae6cef 100644
--- a/pkg/domain/infra/tunnel/events.go
+++ b/pkg/domain/infra/tunnel/events.go
@@ -2,8 +2,10 @@ package tunnel
import (
"context"
+ // "fmt"
"strings"
+ "github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/pkg/bindings/system"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -29,3 +31,33 @@ func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptio
}()
return system.Events(ic.ClientCxt, binChan, nil, &opts.Since, &opts.Until, filters, &opts.Stream)
}
+
+// GetLastContainerEvent takes a container name or ID and an event status and returns
+// the last occurrence of the container event
+func (ic *ContainerEngine) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
+ // check to make sure the event.Status is valid
+ if _, err := events.StringToStatus(containerEvent.String()); err != nil {
+ return nil, err
+ }
+ var event events.Event
+ return &event, nil
+
+ /*
+ FIXME: We need new bindings for this section
+ filters := []string{
+ fmt.Sprintf("container=%s", nameOrID),
+ fmt.Sprintf("event=%s", containerEvent),
+ "type=container",
+ }
+
+ containerEvents, err := system.GetEvents(ctx, entities.EventsOptions{Filter: filters})
+ if err != nil {
+ return nil, err
+ }
+ if len(containerEvents) < 1 {
+ return nil, errors.Wrapf(events.ErrEventNotFound, "%s not found", containerEvent.String())
+ }
+ // return the last element in the slice
+ return containerEvents[len(containerEvents)-1], nil
+ */
+}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 0c38a3326..5944f855a 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -13,7 +13,7 @@ import (
"github.com/pkg/errors"
)
-func getContainersByContext(contextWithConnection context.Context, all bool, namesOrIDs []string) ([]entities.ListContainer, error) {
+func getContainersByContext(contextWithConnection context.Context, all, ignore bool, namesOrIDs []string) ([]entities.ListContainer, error) {
var (
cons []entities.ListContainer
)
@@ -36,7 +36,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
break
}
}
- if !found {
+ if !found && !ignore {
return nil, errors.Wrapf(define.ErrNoSuchCtr, "unable to find container %q", id)
}
}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 50b8342a3..981884109 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -199,6 +199,13 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
return nil, err
}
defer f.Close()
+ fInfo, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ if fInfo.IsDir() {
+ return nil, errors.Errorf("remote client supports archives only but %q is a directory", opts.Input)
+ }
ref := opts.Name
if len(opts.Tag) > 0 {
ref += ":" + opts.Tag
@@ -306,7 +313,22 @@ func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
}
func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) {
- return images.Build(ir.ClientCxt, containerFiles, opts)
+ report, err := images.Build(ir.ClientCxt, containerFiles, opts)
+ if err != nil {
+ return nil, err
+ }
+ // For remote clients, if the option for writing to a file was
+ // selected, we need to write to the *client's* filesystem.
+ if len(opts.IIDFile) > 0 {
+ f, err := os.Create(opts.IIDFile)
+ if err != nil {
+ return nil, err
+ }
+ if _, err := f.WriteString(report.ID); err != nil {
+ return nil, err
+ }
+ }
+ return report, nil
}
func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
diff --git a/pkg/hooks/1.0.0/hook.go b/pkg/hooks/1.0.0/hook.go
index 77fbab5aa..244e8800f 100644
--- a/pkg/hooks/1.0.0/hook.go
+++ b/pkg/hooks/1.0.0/hook.go
@@ -67,7 +67,14 @@ func (hook *Hook) Validate(extensionStages []string) (err error) {
return errors.New("missing required property: stages")
}
- validStages := map[string]bool{"prestart": true, "poststart": true, "poststop": true}
+ validStages := map[string]bool{
+ "createContainer": true,
+ "createRuntime": true,
+ "prestart": true,
+ "poststart": true,
+ "poststop": true,
+ "startContainer": true,
+ }
for _, stage := range extensionStages {
validStages[stage] = true
}
diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go
index 2a12eceac..6257529ab 100644
--- a/pkg/hooks/hooks.go
+++ b/pkg/hooks/hooks.go
@@ -120,12 +120,18 @@ func (m *Manager) Hooks(config *rspec.Spec, annotations map[string]string, hasBi
extensionStageHooks[stage] = append(extensionStageHooks[stage], namedHook.hook.Hook)
} else {
switch stage {
+ case "createContainer":
+ config.Hooks.CreateContainer = append(config.Hooks.CreateContainer, namedHook.hook.Hook)
+ case "createRuntime":
+ config.Hooks.CreateRuntime = append(config.Hooks.CreateRuntime, namedHook.hook.Hook)
case "prestart":
config.Hooks.Prestart = append(config.Hooks.Prestart, namedHook.hook.Hook)
case "poststart":
config.Hooks.Poststart = append(config.Hooks.Poststart, namedHook.hook.Hook)
case "poststop":
config.Hooks.Poststop = append(config.Hooks.Poststop, namedHook.hook.Hook)
+ case "startContainer":
+ config.Hooks.StartContainer = append(config.Hooks.StartContainer, namedHook.hook.Hook)
default:
return extensionStageHooks, fmt.Errorf("hook %q: unknown stage %q", namedHook.name, stage)
}
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index 7f55317ff..b225f79ee 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -195,9 +195,9 @@ func getVolumesFrom(volumesFrom []string, runtime *libpod.Runtime) (map[string]s
splitVol := strings.SplitN(volume, ":", 2)
if len(splitVol) == 2 {
splitOpts := strings.Split(splitVol[1], ",")
+ setRORW := false
+ setZ := false
for _, opt := range splitOpts {
- setRORW := false
- setZ := false
switch opt {
case "z":
if setZ {
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index a4fdae46e..8090bcd3d 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -256,7 +256,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
}
if info.PodmanVersion == "" {
- info.PodmanVersion = version.Version
+ info.PodmanVersion = version.Version.String()
}
if info.GenerateTimestamp {
info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate))
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index c41eedd17..c0acba37d 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -299,7 +299,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
info.ExecStopPost = "{{.Executable}} pod rm --ignore -f --pod-id-file {{.PodIDFile}}"
}
if info.PodmanVersion == "" {
- info.PodmanVersion = version.Version
+ info.PodmanVersion = version.Version.String()
}
if info.GenerateTimestamp {
info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate))
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 9e4db2611..e5c766a6d 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -7,6 +7,7 @@ import (
"fmt"
"os"
goruntime "runtime"
+ "strconv"
"time"
"github.com/containers/image/v5/pkg/sysregistriesv2"
@@ -22,13 +23,18 @@ func (i *VarlinkAPI) GetVersion(call iopodman.VarlinkCall) error {
return err
}
+ int64APIVersion, err := strconv.ParseInt(versionInfo.APIVersion, 10, 64)
+ if err != nil {
+ return err
+ }
+
return call.ReplyGetVersion(
versionInfo.Version,
versionInfo.GoVersion,
versionInfo.GitCommit,
time.Unix(versionInfo.Built, 0).Format(time.RFC3339),
versionInfo.OsArch,
- versionInfo.APIVersion,
+ int64APIVersion,
)
}