summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_attach.go35
-rw-r--r--pkg/api/handlers/compat/events.go19
-rw-r--r--pkg/api/handlers/compat/images_search.go1
-rw-r--r--pkg/api/handlers/libpod/containers.go20
-rw-r--r--pkg/api/handlers/libpod/images.go53
-rw-r--r--pkg/api/handlers/libpod/pods.go3
-rw-r--r--pkg/api/handlers/types.go25
-rw-r--r--pkg/api/server/handler_api.go9
-rw-r--r--pkg/api/server/register_containers.go34
-rw-r--r--pkg/api/server/register_images.go2
-rw-r--r--pkg/api/server/server.go173
-rw-r--r--pkg/bindings/containers/containers.go19
-rw-r--r--pkg/bindings/images/images.go33
-rw-r--r--pkg/bindings/images/search.go41
-rw-r--r--pkg/bindings/test/containers_test.go21
-rw-r--r--pkg/bindings/test/images_test.go21
-rw-r--r--pkg/cgroups/pids.go2
-rw-r--r--pkg/domain/entities/container_ps.go171
-rw-r--r--pkg/domain/entities/containers.go44
-rw-r--r--pkg/domain/entities/engine.go319
-rw-r--r--pkg/domain/entities/engine_container.go6
-rw-r--r--pkg/domain/entities/engine_image.go4
-rw-r--r--pkg/domain/entities/images.go44
-rw-r--r--pkg/domain/entities/pods.go5
-rw-r--r--pkg/domain/entities/types.go10
-rw-r--r--pkg/domain/infra/abi/containers.go105
-rw-r--r--pkg/domain/infra/abi/events.go18
-rw-r--r--pkg/domain/infra/abi/images.go53
-rw-r--r--pkg/domain/infra/abi/pods.go6
-rw-r--r--pkg/domain/infra/abi/system.go155
-rw-r--r--pkg/domain/infra/runtime_abi.go4
-rw-r--r--pkg/domain/infra/runtime_image_proxy.go2
-rw-r--r--pkg/domain/infra/runtime_libpod.go58
-rw-r--r--pkg/domain/infra/runtime_proxy.go2
-rw-r--r--pkg/domain/infra/runtime_tunnel.go4
-rw-r--r--pkg/domain/infra/tunnel/containers.go33
-rw-r--r--pkg/domain/infra/tunnel/events.go31
-rw-r--r--pkg/domain/infra/tunnel/helpers.go2
-rw-r--r--pkg/domain/infra/tunnel/images.go9
-rw-r--r--pkg/ps/ps.go34
-rw-r--r--pkg/rootless/rootless_linux.c5
-rw-r--r--pkg/signal/signal_linux.go7
-rw-r--r--pkg/specgen/config_linux_nocgo.go11
-rw-r--r--pkg/specgen/generate/config_linux_cgo.go (renamed from pkg/specgen/config_linux_cgo.go)5
-rw-r--r--pkg/specgen/generate/config_linux_nocgo.go14
-rw-r--r--pkg/specgen/generate/container_create.go14
-rw-r--r--pkg/specgen/generate/namespaces.go417
-rw-r--r--pkg/specgen/generate/oci.go (renamed from pkg/specgen/oci.go)19
-rw-r--r--pkg/specgen/generate/pod_create.go (renamed from pkg/specgen/pod_create.go)18
-rw-r--r--pkg/specgen/generate/storage.go (renamed from pkg/specgen/storage.go)8
-rw-r--r--pkg/specgen/namespaces.go379
-rw-r--r--pkg/specgen/pod_validate.go5
-rw-r--r--pkg/specgen/specgen.go11
-rw-r--r--pkg/util/utils.go2
54 files changed, 1644 insertions, 901 deletions
diff --git a/pkg/api/handlers/compat/containers_attach.go b/pkg/api/handlers/compat/containers_attach.go
index da7b5bb0c..80ad52aee 100644
--- a/pkg/api/handlers/compat/containers_attach.go
+++ b/pkg/api/handlers/compat/containers_attach.go
@@ -1,6 +1,7 @@
package compat
import (
+ "fmt"
"net/http"
"github.com/containers/libpod/libpod"
@@ -23,7 +24,9 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
Stdin bool `schema:"stdin"`
Stdout bool `schema:"stdout"`
Stderr bool `schema:"stderr"`
- }{}
+ }{
+ Stream: true,
+ }
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, "Error parsing parameters", http.StatusBadRequest, err)
return
@@ -61,16 +64,9 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
return
}
- // TODO: Investigate supporting these.
- // Logs replays container logs over the attach socket.
- // Stream seems to break things up somehow? Not 100% clear.
- if query.Logs {
- utils.Error(w, "Unsupported parameter", http.StatusBadRequest, errors.Errorf("the logs parameter to attach is not presently supported"))
- return
- }
- // We only support stream=true or unset
- if _, found := r.URL.Query()["stream"]; found && query.Stream {
- utils.Error(w, "Unsupported parameter", http.StatusBadRequest, errors.Errorf("the stream parameter to attach is not presently supported"))
+ // At least one of these must be set
+ if !query.Stream && !query.Logs {
+ utils.Error(w, "Unsupported parameter", http.StatusBadRequest, errors.Errorf("at least one of Logs or Stream must be set"))
return
}
@@ -86,7 +82,13 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- if !(state == define.ContainerStateCreated || state == define.ContainerStateRunning) {
+ // For Docker compatibility, we need to re-initialize containers in these states.
+ if state == define.ContainerStateConfigured || state == define.ContainerStateExited {
+ if err := ctr.Init(r.Context()); err != nil {
+ utils.InternalServerError(w, errors.Wrapf(err, "error preparing container %s for attach", ctr.ID()))
+ return
+ }
+ } else if !(state == define.ContainerStateCreated || state == define.ContainerStateRunning) {
utils.InternalServerError(w, errors.Wrapf(define.ErrCtrStateInvalid, "can only attach to created or running containers"))
return
}
@@ -98,20 +100,23 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
return
}
- w.WriteHeader(http.StatusSwitchingProtocols)
-
connection, buffer, err := hijacker.Hijack()
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "error hijacking connection"))
return
}
+ // This header string sourced from Docker:
+ // https://raw.githubusercontent.com/moby/moby/b95fad8e51bd064be4f4e58a996924f343846c85/api/server/router/container/container_routes.go
+ // Using literally to ensure compatability with existing clients.
+ fmt.Fprintf(connection, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
+
logrus.Debugf("Hijack for attach of container %s successful", ctr.ID())
// Perform HTTP attach.
// HTTPAttach will handle everything about the connection from here on
// (including closing it and writing errors to it).
- if err := ctr.HTTPAttach(connection, buffer, streams, detachKeys, nil); err != nil {
+ if err := ctr.HTTPAttach(connection, buffer, streams, detachKeys, nil, query.Stream, query.Logs); err != nil {
// We can't really do anything about errors anymore. HTTPAttach
// should be writing them to the connection.
logrus.Errorf("Error attaching to container %s: %v", ctr.ID(), err)
diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go
index 0f72ef328..8ef32716d 100644
--- a/pkg/api/handlers/compat/events.go
+++ b/pkg/api/handlers/compat/events.go
@@ -1,7 +1,6 @@
package compat
import (
- "encoding/json"
"fmt"
"net/http"
@@ -10,6 +9,7 @@ import (
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/gorilla/schema"
+ jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -48,14 +48,27 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
}()
if eventsError != nil {
utils.InternalServerError(w, eventsError)
+ close(eventChannel)
return
}
- coder := json.NewEncoder(w)
- coder.SetEscapeHTML(true)
+ // If client disappears we need to stop listening for events
+ go func(done <-chan struct{}) {
+ <-done
+ close(eventChannel)
+ }(r.Context().Done())
+ // Headers need to be written out before turning Writer() over to json encoder
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ coder := json.NewEncoder(w)
+ coder.SetEscapeHTML(true)
+
for event := range eventChannel {
e := handlers.EventToApiEvent(event)
if err := coder.Encode(e); err != nil {
diff --git a/pkg/api/handlers/compat/images_search.go b/pkg/api/handlers/compat/images_search.go
index 7283b22c4..8da685527 100644
--- a/pkg/api/handlers/compat/images_search.go
+++ b/pkg/api/handlers/compat/images_search.go
@@ -57,6 +57,7 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
Filter: filter,
Limit: query.Limit,
}
+
results, err := image.SearchImages(query.Term, options)
if err != nil {
utils.BadRequest(w, "term", query.Term, err)
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 5cbfb11eb..086bef847 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -285,3 +285,23 @@ func Restore(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusOK, entities.RestoreReport{Id: ctr.ID()})
}
+
+func InitContainer(w http.ResponseWriter, r *http.Request) {
+ name := utils.GetName(r)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ err = ctr.Init(r.Context())
+ if errors.Cause(err) == define.ErrCtrStateInvalid {
+ utils.Error(w, "container already initialized", http.StatusNotModified, err)
+ return
+ }
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusNoContent, "")
+}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 850de4598..a42d06205 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -645,3 +645,56 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusCreated, "")
}
+
+func SearchImages(w http.ResponseWriter, r *http.Request) {
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Term string `json:"term"`
+ Limit int `json:"limit"`
+ Filters []string `json:"filters"`
+ TLSVerify bool `json:"tlsVerify"`
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+
+ 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
+ }
+
+ options := image.SearchOptions{
+ Limit: query.Limit,
+ }
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ if _, found := r.URL.Query()["filters"]; found {
+ filter, err := image.ParseSearchFilter(query.Filters)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse filters parameter for %s", r.URL.String()))
+ return
+ }
+ options.Filter = *filter
+ }
+
+ searchResults, err := image.SearchImages(query.Term, options)
+ if err != nil {
+ utils.BadRequest(w, "term", query.Term, err)
+ return
+ }
+ // Convert from image.SearchResults to entities.ImageSearchReport. We don't
+ // want to leak any low-level packages into the remote client, which
+ // requires converting.
+ reports := make([]entities.ImageSearchReport, len(searchResults))
+ for i := range searchResults {
+ reports[i].Index = searchResults[i].Index
+ reports[i].Name = searchResults[i].Name
+ reports[i].Description = searchResults[i].Index
+ reports[i].Stars = searchResults[i].Stars
+ reports[i].Official = searchResults[i].Official
+ reports[i].Automated = searchResults[i].Automated
+ }
+
+ utils.WriteResponse(w, http.StatusOK, reports)
+}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index a890169a1..81cab1ede 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/specgen/generate"
"github.com/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -27,7 +28,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Failed to decode specgen", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
return
}
- pod, err := psg.MakePod(runtime)
+ pod, err := generate.MakePod(&psg, runtime)
if err != nil {
http_code := http.StatusInternalServerError
if errors.Cause(err) == define.ErrPodExists {
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index f1c932ebc..0fe6ae6a7 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -180,6 +180,31 @@ type ExecCreateResponse struct {
docker.IDResponse
}
+func (e *Event) ToLibpodEvent() *events.Event {
+ exitCode, err := strconv.Atoi(e.Actor.Attributes["containerExitCode"])
+ if err != nil {
+ return nil
+ }
+ status, err := events.StringToStatus(e.Action)
+ if err != nil {
+ return nil
+ }
+ t, err := events.StringToType(e.Type)
+ if err != nil {
+ return nil
+ }
+ lp := events.Event{
+ ContainerExitCode: exitCode,
+ ID: e.Actor.ID,
+ Image: e.Actor.Attributes["image"],
+ Name: e.Actor.Attributes["name"],
+ Status: status,
+ Time: time.Unix(e.Time, e.TimeNano),
+ Type: t,
+ }
+ return &lp
+}
+
func EventToApiEvent(e *events.Event) *Event {
return &Event{dockerEvents.Message{
Type: e.Type.String(),
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index 30a1680c9..7a7db12f3 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -19,7 +19,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
if err != nil {
buf := make([]byte, 1<<20)
n := runtime.Stack(buf, true)
- log.Warnf("Recovering from podman handler panic: %v, %s", err, buf[:n])
+ log.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
// Try to inform client things went south... won't work if handler already started writing response body
utils.InternalServerError(w, fmt.Errorf("%v", err))
}
@@ -27,12 +27,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
// Wrapper to hide some boiler plate
fn := func(w http.ResponseWriter, r *http.Request) {
- // Connection counting, ugh. Needed to support the sliding window for idle checking.
- s.ConnectionCh <- EnterHandler
- defer func() { s.ConnectionCh <- ExitHandler }()
-
- log.Debugf("APIHandler -- Method: %s URL: %s (conn %d/%d)",
- r.Method, r.URL.String(), s.ActiveConnections, s.TotalConnections)
+ log.Debugf("APIHandler -- Method: %s URL: %s", r.Method, r.URL.String())
if err := r.ParseForm(); err != nil {
log.Infof("Failed Request: unable to parse form: %q", err)
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 150cca872..8b9a9e312 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -517,13 +517,13 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// name: logs
// required: false
// type: boolean
- // description: Not yet supported
+ // description: Stream all logs from the container across the connection. Happens before streaming attach (if requested). At least one of logs or stream must be set
// - in: query
// name: stream
// required: false
// type: boolean
// default: true
- // description: If passed, must be set to true; stream=false is not yet supported
+ // description: Attach to the container. If unset, and logs is set, only the container's logs will be sent. At least one of stream or logs must be set
// - in: query
// name: stdout
// required: false
@@ -1194,13 +1194,13 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// name: logs
// required: false
// type: boolean
- // description: Not yet supported
+ // description: Stream all logs from the container across the connection. Happens before streaming attach (if requested). At least one of logs or stream must be set
// - in: query
// name: stream
// required: false
// type: boolean
// default: true
- // description: If passed, must be set to true; stream=false is not yet supported
+ // description: Attach to the container. If unset, and logs is set, only the container's logs will be sent. At least one of stream or logs must be set
// - in: query
// name: stdout
// required: false
@@ -1377,7 +1377,6 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/{name}/restore"), s.APIHandler(libpod.Restore)).Methods(http.MethodPost)
-
// swagger:operation GET /containers/{name}/changes libpod libpodChangesContainer
// swagger:operation GET /libpod/containers/{name}/changes compat changesContainer
// ---
@@ -1411,6 +1410,29 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
r.HandleFunc(VersionedPath("/containers/{name}/changes"), s.APIHandler(compat.Changes))
r.HandleFunc("/containers/{name}/changes", s.APIHandler(compat.Changes))
r.HandleFunc(VersionedPath("/libpod/containers/{name}/changes"), s.APIHandler(compat.Changes))
-
+ // swagger:operation POST /libpod/containers/{name}/init libpod libpodInitContainer
+ // ---
+ // tags:
+ // - containers
+ // summary: Initialize a container
+ // description: Performs all tasks necessary for initializing the container but does not start the container.
+ // parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // 204:
+ // description: no error
+ // 304:
+ // description: container already initialized
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/init"), s.APIHandler(libpod.InitContainer)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 77560e789..7dd887037 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -919,7 +919,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// $ref: "#/responses/DocsSearchResponse"
// 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/search"), s.APIHandler(compat.SearchImages)).Methods(http.MethodGet)
+ r.Handle(VersionedPath("/libpod/images/search"), s.APIHandler(libpod.SearchImages)).Methods(http.MethodGet)
// swagger:operation DELETE /libpod/images/{name:.*} libpod libpodRemoveImage
// ---
// tags:
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index c1ec6aca8..5f1a86183 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -2,11 +2,14 @@ package server
import (
"context"
+ "log"
"net"
"net/http"
"os"
"os/signal"
+ "runtime"
"strings"
+ "sync"
"syscall"
"time"
@@ -20,26 +23,19 @@ import (
)
type APIServer struct {
- http.Server // The HTTP work happens here
- *schema.Decoder // Decoder for Query parameters to structs
- context.Context // Context to carry objects to handlers
- *libpod.Runtime // Where the real work happens
- net.Listener // mux for routing HTTP API calls to libpod routines
- context.CancelFunc // Stop APIServer
- *time.Timer // Hold timer for sliding window
- time.Duration // Duration of client access sliding window
- ActiveConnections uint64 // Number of handlers holding a connection
- TotalConnections uint64 // Number of connections handled
- ConnectionCh chan int // Channel for signalling handler enter/exit
+ http.Server // The HTTP work happens here
+ *schema.Decoder // Decoder for Query parameters to structs
+ context.Context // Context to carry objects to handlers
+ *libpod.Runtime // Where the real work happens
+ net.Listener // mux for routing HTTP API calls to libpod routines
+ context.CancelFunc // Stop APIServer
+ idleTracker *IdleTracker // Track connections to support idle shutdown
}
// Number of seconds to wait for next request, if exceeded shutdown server
const (
DefaultServiceDuration = 300 * time.Second
UnlimitedServiceDuration = 0 * time.Second
- EnterHandler = 1
- ExitHandler = -1
- NOOPHandler = 0
)
// NewServer will create and configure a new API server with all defaults
@@ -70,17 +66,20 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
}
router := mux.NewRouter().UseEncodedPath()
+ idle := NewIdleTracker(duration)
+
server := APIServer{
Server: http.Server{
Handler: router,
ReadHeaderTimeout: 20 * time.Second,
IdleTimeout: duration,
+ ConnState: idle.ConnState,
+ ErrorLog: log.New(logrus.StandardLogger().Out, "", 0),
},
- Decoder: handlers.NewAPIDecoder(),
- Runtime: runtime,
- Listener: *listener,
- Duration: duration,
- ConnectionCh: make(chan int),
+ Decoder: handlers.NewAPIDecoder(),
+ idleTracker: idle,
+ Listener: *listener,
+ Runtime: runtime,
}
router.NotFoundHandler = http.HandlerFunc(
@@ -120,11 +119,11 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
router.Walk(func(route *mux.Route, r *mux.Router, ancestors []*mux.Route) error { // nolint
path, err := route.GetPathTemplate()
if err != nil {
- path = ""
+ path = "<N/A>"
}
methods, err := route.GetMethods()
if err != nil {
- methods = []string{}
+ methods = []string{"<N/A>"}
}
logrus.Debugf("Methods: %s Path: %s", strings.Join(methods, ", "), path)
return nil
@@ -136,24 +135,20 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
// Serve starts responding to HTTP requests
func (s *APIServer) Serve() error {
- // This is initialized here as Timer is not needed until Serve'ing
- if s.Duration > 0 {
- s.Timer = time.AfterFunc(s.Duration, func() {
- s.ConnectionCh <- NOOPHandler
- })
- go s.ReadChannelWithTimeout()
- } else {
- go s.ReadChannelNoTimeout()
- }
-
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
errChan := make(chan error, 1)
go func() {
+ <-s.idleTracker.Done()
+ logrus.Debugf("API Server idle for %v", s.idleTracker.Duration)
+ _ = s.Shutdown()
+ }()
+
+ go func() {
err := s.Server.Serve(s.Listener)
if err != nil && err != http.ErrServerClosed {
- errChan <- errors.Wrap(err, "Failed to start APIServer")
+ errChan <- errors.Wrap(err, "failed to start API server")
return
}
errChan <- nil
@@ -169,72 +164,30 @@ func (s *APIServer) Serve() error {
return nil
}
-func (s *APIServer) ReadChannelWithTimeout() {
- // stalker to count the connections. Should the timer expire it will shutdown the service.
- for delta := range s.ConnectionCh {
- switch delta {
- case EnterHandler:
- s.Timer.Stop()
- s.ActiveConnections += 1
- s.TotalConnections += 1
- case ExitHandler:
- s.Timer.Stop()
- s.ActiveConnections -= 1
- if s.ActiveConnections == 0 {
- // Server will be shutdown iff the timer expires before being reset or stopped
- s.Timer = time.AfterFunc(s.Duration, func() {
- if err := s.Shutdown(); err != nil {
- logrus.Errorf("Failed to shutdown APIServer: %v", err)
- os.Exit(1)
- }
- })
- } else {
- s.Timer.Reset(s.Duration)
- }
- case NOOPHandler:
- // push the check out another duration...
- s.Timer.Reset(s.Duration)
- default:
- logrus.Warnf("ConnectionCh received unsupported input %d", delta)
- }
- }
-}
-
-func (s *APIServer) ReadChannelNoTimeout() {
- // stalker to count the connections.
- for delta := range s.ConnectionCh {
- switch delta {
- case EnterHandler:
- s.ActiveConnections += 1
- s.TotalConnections += 1
- case ExitHandler:
- s.ActiveConnections -= 1
- case NOOPHandler:
- default:
- logrus.Warnf("ConnectionCh received unsupported input %d", delta)
- }
- }
-}
-
// Shutdown is a clean shutdown waiting on existing clients
func (s *APIServer) Shutdown() error {
+ if logrus.IsLevelEnabled(logrus.DebugLevel) {
+ _, file, line, _ := runtime.Caller(1)
+ logrus.Debugf("APIServer.Shutdown by %s:%d, %d/%d connection(s)",
+ file, line, s.idleTracker.ActiveConnections(), s.idleTracker.TotalConnections())
+ }
+
// Duration == 0 flags no auto-shutdown of the server
- if s.Duration == 0 {
+ if s.idleTracker.Duration == 0 {
logrus.Debug("APIServer.Shutdown ignored as Duration == 0")
return nil
}
- logrus.Debugf("APIServer.Shutdown called %v, conn %d/%d", time.Now(), s.ActiveConnections, s.TotalConnections)
- // Gracefully shutdown server
- ctx, cancel := context.WithTimeout(context.Background(), s.Duration)
+ // Gracefully shutdown server, duration of wait same as idle window
+ ctx, cancel := context.WithTimeout(context.Background(), s.idleTracker.Duration)
defer cancel()
-
go func() {
err := s.Server.Shutdown(ctx)
if err != nil && err != context.Canceled && err != http.ErrServerClosed {
logrus.Errorf("Failed to cleanly shutdown APIServer: %s", err.Error())
}
}()
+ <-ctx.Done()
return nil
}
@@ -242,3 +195,55 @@ func (s *APIServer) Shutdown() error {
func (s *APIServer) Close() error {
return s.Server.Close()
}
+
+type IdleTracker struct {
+ active map[net.Conn]struct{}
+ total int
+ mux sync.Mutex
+ timer *time.Timer
+ Duration time.Duration
+}
+
+func NewIdleTracker(idle time.Duration) *IdleTracker {
+ return &IdleTracker{
+ active: make(map[net.Conn]struct{}),
+ Duration: idle,
+ timer: time.NewTimer(idle),
+ }
+}
+
+func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState) {
+ t.mux.Lock()
+ defer t.mux.Unlock()
+
+ oldActive := len(t.active)
+ logrus.Debugf("IdleTracker %p:%v %d/%d connection(s)", conn, state, t.ActiveConnections(), t.TotalConnections())
+ switch state {
+ case http.StateNew, http.StateActive, http.StateHijacked:
+ t.active[conn] = struct{}{}
+ // stop the timer if we transitioned from idle
+ if oldActive == 0 {
+ t.timer.Stop()
+ }
+ t.total += 1
+ case http.StateIdle, http.StateClosed:
+ delete(t.active, conn)
+ // Restart the timer if we've become idle
+ if oldActive > 0 && len(t.active) == 0 {
+ t.timer.Stop()
+ t.timer.Reset(t.Duration)
+ }
+ }
+}
+
+func (t *IdleTracker) ActiveConnections() int {
+ return len(t.active)
+}
+
+func (t *IdleTracker) TotalConnections() int {
+ return t.total
+}
+
+func (t *IdleTracker) Done() <-chan time.Time {
+ return t.timer.C
+}
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index a188d73a0..963f0ec57 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
)
// List obtains a list of containers in local storage. All parameters to this method are optional.
@@ -316,3 +317,21 @@ func Export(ctx context.Context, nameOrID string, w io.Writer) error {
}
return response.Process(nil)
}
+
+// ContainerInit takes a created container and executes all of the
+// preparations to run the container except it will not start
+// or attach to the container
+func ContainerInit(ctx context.Context, nameOrID string) error {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return err
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/init", nil, nameOrID)
+ if err != nil {
+ return err
+ }
+ if response.StatusCode == http.StatusNotModified {
+ return errors.Wrapf(define.ErrCtrStateInvalid, "container %s has already been created in runtime", nameOrID)
+ }
+ return response.Process(nil)
+}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 1b3df609b..3550c3968 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -2,7 +2,6 @@ package images
import (
"context"
- "errors"
"fmt"
"io"
"net/http"
@@ -13,6 +12,7 @@ import (
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
)
// Exists a lightweight way to determine if an image exists in local storage. It returns a
@@ -308,3 +308,34 @@ func Push(ctx context.Context, source string, destination string, options entiti
_, err = conn.DoRequest(nil, http.MethodPost, path, params)
return err
}
+
+// Search is the binding for libpod's v2 endpoints for Search images.
+func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("term", term)
+ params.Set("limit", strconv.Itoa(opts.Limit))
+ for _, f := range opts.Filters {
+ params.Set("filters", f)
+ }
+
+ if opts.TLSVerify != types.OptionalBoolUndefined {
+ val := bool(opts.TLSVerify == types.OptionalBoolTrue)
+ params.Set("tlsVerify", strconv.FormatBool(val))
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params)
+ if err != nil {
+ return nil, err
+ }
+
+ results := []entities.ImageSearchReport{}
+ if err := response.Process(&results); err != nil {
+ return nil, err
+ }
+
+ return results, nil
+}
diff --git a/pkg/bindings/images/search.go b/pkg/bindings/images/search.go
deleted file mode 100644
index 183ff3d77..000000000
--- a/pkg/bindings/images/search.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package images
-
-import (
- "context"
- "net/http"
- "net/url"
- "strconv"
-
- "github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/bindings"
-)
-
-// Search looks for the given image (term) in container image registries. The optional limit parameter sets
-// a maximum number of results returned. The optional filters parameter allow for more specific image
-// searches.
-func Search(ctx context.Context, term string, limit *int, filters map[string][]string) ([]image.SearchResult, error) {
- var (
- searchResults []image.SearchResult
- )
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
- params := url.Values{}
- params.Set("term", term)
- if limit != nil {
- params.Set("limit", strconv.Itoa(*limit))
- }
- if filters != nil {
- stringFilter, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", stringFilter)
- }
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params)
- if err != nil {
- return searchResults, nil
- }
- return searchResults, response.Process(&searchResults)
-}
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index d3fc80eea..0b1b9ecdd 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -508,8 +508,27 @@ var _ = Describe("Podman containers ", func() {
_, err = bt.RunTopContainer(&name2, &bindings.PFalse, nil)
Expect(err).To(BeNil())
containerLatestList, err := containers.List(bt.conn, nil, nil, &latestContainers, nil, nil, nil)
- err = containers.Kill(bt.conn, containerLatestList[0].Names(), "SIGTERM")
Expect(err).To(BeNil())
+ err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM")
+ Expect(err).To(BeNil())
+ })
+
+ It("container init on a bogus container", func() {
+ err := containers.ContainerInit(bt.conn, "doesnotexist")
+ Expect(err).ToNot(BeNil())
+ code, _ := bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotFound))
+ })
+
+ It("container init", func() {
+ s := specgen.NewSpecGenerator(alpine.name)
+ ctr, err := containers.CreateWithSpec(bt.conn, s)
+ Expect(err).To(BeNil())
+ err = containers.ContainerInit(bt.conn, ctr.ID)
+ Expect(err).To(BeNil())
+ // trying to init again should be an error
+ err = containers.ContainerInit(bt.conn, ctr.ID)
+ Expect(err).ToNot(BeNil())
})
})
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 992720196..58210efd0 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -314,11 +314,11 @@ var _ = Describe("Podman images", func() {
})
It("Search for an image", func() {
- imgs, err := images.Search(bt.conn, "alpine", nil, nil)
+ reports, err := images.Search(bt.conn, "alpine", entities.ImageSearchOptions{})
Expect(err).To(BeNil())
- Expect(len(imgs)).To(BeNumerically(">", 1))
+ Expect(len(reports)).To(BeNumerically(">", 1))
var foundAlpine bool
- for _, i := range imgs {
+ for _, i := range reports {
if i.Name == "docker.io/library/alpine" {
foundAlpine = true
break
@@ -327,23 +327,20 @@ var _ = Describe("Podman images", func() {
Expect(foundAlpine).To(BeTrue())
// Search for alpine with a limit of 10
- ten := 10
- imgs, err = images.Search(bt.conn, "docker.io/alpine", &ten, nil)
+ reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Limit: 10})
Expect(err).To(BeNil())
- Expect(len(imgs)).To(BeNumerically("<=", 10))
+ Expect(len(reports)).To(BeNumerically("<=", 10))
// Search for alpine with stars greater than 100
- filters := make(map[string][]string)
- filters["stars"] = []string{"100"}
- imgs, err = images.Search(bt.conn, "docker.io/alpine", nil, filters)
+ reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Filters: []string{"stars=100"}})
Expect(err).To(BeNil())
- for _, i := range imgs {
+ for _, i := range reports {
Expect(i.Stars).To(BeNumerically(">=", 100))
}
// Search with a fqdn
- imgs, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", nil, nil)
- Expect(len(imgs)).To(BeNumerically(">=", 1))
+ reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", entities.ImageSearchOptions{})
+ Expect(len(reports)).To(BeNumerically(">=", 1))
})
It("Prune images", func() {
diff --git a/pkg/cgroups/pids.go b/pkg/cgroups/pids.go
index 92f82553b..b2bfebe4d 100644
--- a/pkg/cgroups/pids.go
+++ b/pkg/cgroups/pids.go
@@ -44,7 +44,7 @@ func (c *pidHandler) Destroy(ctr *CgroupControl) error {
// Stat fills a metrics structure with usage stats for the controller
func (c *pidHandler) Stat(ctr *CgroupControl, m *Metrics) error {
- if ctr.path != "" {
+ if ctr.path == "" {
// nothing we can do to retrieve the pids.current path
return nil
}
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index f07b0364f..ceafecebc 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -1,23 +1,19 @@
package entities
import (
- "fmt"
"sort"
- "strconv"
"strings"
- "time"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/go-units"
"github.com/pkg/errors"
)
// Listcontainer describes a container suitable for listing
type ListContainer struct {
// Container command
- Cmd []string
+ Command []string
// Container creation time
Created int64
// If container has exited/stopped
@@ -37,7 +33,7 @@ type ListContainer struct {
// User volume mounts
Mounts []string
// The names assigned to the container
- ContainerNames []string
+ Names []string
// Namespaces the container belongs to. Requires the
// namespace boolean to be true
Namespaces ListContainerNamespaces
@@ -50,69 +46,13 @@ type ListContainer struct {
// boolean to be set
PodName string
// Port mappings
- PortMappings []ocicni.PortMapping
+ Ports []ocicni.PortMapping
// Size of the container rootfs. Requires the size boolean to be true
- ContainerSize *shared.ContainerSize
+ Size *shared.ContainerSize
// Time when container started
StartedAt int64
// State of container
- ContainerState string
-}
-
-// State returns the container state in human duration
-func (l ListContainer) State() string {
- var state string
- switch l.ContainerState {
- case "running":
- t := units.HumanDuration(time.Since(time.Unix(l.StartedAt, 0)))
- state = "Up " + t + " ago"
- case "configured":
- state = "Created"
- case "exited", "stopped":
- t := units.HumanDuration(time.Since(time.Unix(l.ExitedAt, 0)))
- state = fmt.Sprintf("Exited (%d) %s ago", l.ExitCode, t)
- default:
- state = l.ContainerState
- }
- return state
-}
-
-// Command returns the container command in string format
-func (l ListContainer) Command() string {
- return strings.Join(l.Cmd, " ")
-}
-
-// Size returns the rootfs and virtual sizes in human duration in
-// and output form (string) suitable for ps
-func (l ListContainer) Size() string {
- virt := units.HumanSizeWithPrecision(float64(l.ContainerSize.RootFsSize), 3)
- s := units.HumanSizeWithPrecision(float64(l.ContainerSize.RwSize), 3)
- return fmt.Sprintf("%s (virtual %s)", s, virt)
-}
-
-// Names returns the container name in string format
-func (l ListContainer) Names() string {
- return l.ContainerNames[0]
-}
-
-// Ports converts from Portmappings to the string form
-// required by ps
-func (l ListContainer) Ports() string {
- if len(l.PortMappings) < 1 {
- return ""
- }
- return portsToString(l.PortMappings)
-}
-
-// CreatedAt returns the container creation time in string format. podman
-// and docker both return a timestamped value for createdat
-func (l ListContainer) CreatedAt() string {
- return time.Unix(l.Created, 0).String()
-}
-
-// CreateHuman allows us to output the created time in human readable format
-func (l ListContainer) CreatedHuman() string {
- return units.HumanDuration(time.Since(time.Unix(l.Created, 0))) + " ago"
+ State string
}
// ListContainer Namespaces contains the identifiers of the container's Linux namespaces
@@ -153,7 +93,7 @@ func (a SortListContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type psSortedCommand struct{ SortListContainers }
func (a psSortedCommand) Less(i, j int) bool {
- return strings.Join(a.SortListContainers[i].Cmd, " ") < strings.Join(a.SortListContainers[j].Cmd, " ")
+ return strings.Join(a.SortListContainers[i].Command, " ") < strings.Join(a.SortListContainers[j].Command, " ")
}
type psSortedId struct{ SortListContainers }
@@ -171,7 +111,7 @@ func (a psSortedImage) Less(i, j int) bool {
type psSortedNames struct{ SortListContainers }
func (a psSortedNames) Less(i, j int) bool {
- return a.SortListContainers[i].ContainerNames[0] < a.SortListContainers[j].ContainerNames[0]
+ return a.SortListContainers[i].Names[0] < a.SortListContainers[j].Names[0]
}
type psSortedPod struct{ SortListContainers }
@@ -189,16 +129,16 @@ func (a psSortedRunningFor) Less(i, j int) bool {
type psSortedStatus struct{ SortListContainers }
func (a psSortedStatus) Less(i, j int) bool {
- return a.SortListContainers[i].ContainerState < a.SortListContainers[j].ContainerState
+ return a.SortListContainers[i].State < a.SortListContainers[j].State
}
type psSortedSize struct{ SortListContainers }
func (a psSortedSize) Less(i, j int) bool {
- if a.SortListContainers[i].ContainerSize == nil || a.SortListContainers[j].ContainerSize == nil {
+ if a.SortListContainers[i].Size == nil || a.SortListContainers[j].Size == nil {
return false
}
- return a.SortListContainers[i].ContainerSize.RootFsSize < a.SortListContainers[j].ContainerSize.RootFsSize
+ return a.SortListContainers[i].Size.RootFsSize < a.SortListContainers[j].Size.RootFsSize
}
type PsSortedCreateTime struct{ SortListContainers }
@@ -232,94 +172,3 @@ func SortPsOutput(sortBy string, psOutput SortListContainers) (SortListContainer
}
return psOutput, nil
}
-
-// portsToString converts the ports used to a string of the from "port1, port2"
-// and also groups a continuous list of ports into a readable format.
-func portsToString(ports []ocicni.PortMapping) string {
- type portGroup struct {
- first int32
- last int32
- }
- var portDisplay []string
- if len(ports) == 0 {
- return ""
- }
- //Sort the ports, so grouping continuous ports become easy.
- sort.Slice(ports, func(i, j int) bool {
- return comparePorts(ports[i], ports[j])
- })
-
- // portGroupMap is used for grouping continuous ports.
- portGroupMap := make(map[string]*portGroup)
- var groupKeyList []string
-
- for _, v := range ports {
-
- hostIP := v.HostIP
- if hostIP == "" {
- hostIP = "0.0.0.0"
- }
- // If hostPort and containerPort are not same, consider as individual port.
- if v.ContainerPort != v.HostPort {
- portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
- continue
- }
-
- portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
-
- portgroup, ok := portGroupMap[portMapKey]
- if !ok {
- portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
- // This list is required to traverse portGroupMap.
- groupKeyList = append(groupKeyList, portMapKey)
- continue
- }
-
- if portgroup.last == (v.ContainerPort - 1) {
- portgroup.last = v.ContainerPort
- continue
- }
- }
- // For each portMapKey, format group list and appned to output string.
- for _, portKey := range groupKeyList {
- group := portGroupMap[portKey]
- portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
- }
- return strings.Join(portDisplay, ", ")
-}
-
-func comparePorts(i, j ocicni.PortMapping) bool {
- if i.ContainerPort != j.ContainerPort {
- return i.ContainerPort < j.ContainerPort
- }
-
- if i.HostIP != j.HostIP {
- return i.HostIP < j.HostIP
- }
-
- if i.HostPort != j.HostPort {
- return i.HostPort < j.HostPort
- }
-
- return i.Protocol < j.Protocol
-}
-
-// formatGroup returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto>
-// e.g 0.0.0.0:1000-1006->1000-1006/tcp.
-func formatGroup(key string, start, last int32) string {
- parts := strings.Split(key, "/")
- groupType := parts[0]
- var ip string
- if len(parts) > 1 {
- ip = parts[0]
- groupType = parts[1]
- }
- group := strconv.Itoa(int(start))
- if start != last {
- group = fmt.Sprintf("%s-%d", group, last)
- }
- if ip != "" {
- group = fmt.Sprintf("%s:%s->%s", ip, group, group)
- }
- return fmt.Sprintf("%s/%s", group, groupType)
-}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 51e6cc751..f21af9ce4 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -283,3 +283,47 @@ type ContainerCleanupReport struct {
RmErr error
RmiErr error
}
+
+// ContainerInitOptions describes input options
+// for the container init cli
+type ContainerInitOptions struct {
+ All bool
+ Latest bool
+}
+
+// ContainerInitReport describes the results of a
+// container init
+type ContainerInitReport struct {
+ Err error
+ Id string
+}
+
+//ContainerMountOptions describes the input values for mounting containers
+// in the CLI
+type ContainerMountOptions struct {
+ All bool
+ Format string
+ Latest bool
+ NoTruncate bool
+}
+
+// ContainerUnmountOptions are the options from the cli for unmounting
+type ContainerUnmountOptions struct {
+ All bool
+ Force bool
+ Latest bool
+}
+
+// ContainerMountReport describes the response from container mount
+type ContainerMountReport struct {
+ Err error
+ Id string
+ Name string
+ Path string
+}
+
+// ContainerUnmountReport describes the response from umounting a container
+type ContainerUnmountReport struct {
+ Err error
+ Id string
+}
diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go
index c14348529..3b971a1e8 100644
--- a/pkg/domain/entities/engine.go
+++ b/pkg/domain/entities/engine.go
@@ -1,13 +1,23 @@
package entities
import (
- "os/user"
- "path/filepath"
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "github.com/containers/buildah/pkg/parse"
"github.com/containers/common/pkg/config"
+ "github.com/containers/common/pkg/sysinfo"
+ "github.com/containers/libpod/pkg/apparmor"
+ "github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/opencontainers/selinux/go-selinux"
+ "github.com/opentracing/opentracing-go"
"github.com/spf13/pflag"
)
+// EngineMode is the connection type podman is using to access libpod
type EngineMode string
const (
@@ -15,78 +25,243 @@ const (
TunnelMode = EngineMode("tunnel")
)
+// Convert EngineMode to String
func (m EngineMode) String() string {
return string(m)
}
-type EngineOptions struct {
- Uri string
- Identities []string
- FlagSet *pflag.FlagSet
- EngineMode EngineMode
-
- CGroupManager string
- CniConfigDir string
- ConmonPath string
- DefaultMountsFile string
- EventsBackend string
- HooksDir []string
- MaxWorks int
- Namespace string
- Root string
- Runroot string
- Runtime string
- StorageDriver string
- StorageOpts []string
- Syslog bool
- Trace bool
- NetworkCmdPath string
-
- Config string
- CpuProfile string
- LogLevel string
- TmpDir string
-
- RemoteUserName string
- RemoteHost string
- VarlinkAddress string
- ConnectionName string
- RemoteConfigFilePath string
- Port int
- IdentityFile string
- IgnoreHosts bool
-}
-
-func NewEngineOptions() (EngineOptions, error) {
- u, _ := user.Current()
- return EngineOptions{
- CGroupManager: config.SystemdCgroupsManager,
- CniConfigDir: "",
- Config: "",
- ConmonPath: filepath.Join("usr", "bin", "conmon"),
- ConnectionName: "",
- CpuProfile: "",
- DefaultMountsFile: "",
- EventsBackend: "",
- HooksDir: nil,
- IdentityFile: "",
- IgnoreHosts: false,
- LogLevel: "",
- MaxWorks: 0,
- Namespace: "",
- NetworkCmdPath: "",
- Port: 0,
- RemoteConfigFilePath: "",
- RemoteHost: "",
- RemoteUserName: "",
- Root: "",
- Runroot: filepath.Join("run", "user", u.Uid),
- Runtime: "",
- StorageDriver: "overlayfs",
- StorageOpts: nil,
- Syslog: false,
- TmpDir: filepath.Join("run", "user", u.Uid, "libpod", "tmp"),
- Trace: false,
- VarlinkAddress: "",
- }, nil
+// PodmanConfig combines the defaults and settings from the file system with the
+// flags given in os.Args. Some runtime state is also stored here.
+type PodmanConfig struct {
+ *config.Config
+ *pflag.FlagSet
+
+ CGroupUsage string // rootless code determines Usage message
+ ConmonPath string // --conmon flag will set Engine.ConmonPath
+ CpuProfile string // Hidden: Should CPU profile be taken
+ EngineMode EngineMode // ABI or Tunneling mode
+ Identities []string // ssh identities for connecting to server
+ MaxWorks int // maximum number of parallel threads
+ RuntimePath string // --runtime flag will set Engine.RuntimePath
+ SpanCloser io.Closer // Close() for tracing object
+ SpanCtx context.Context // context to use when tracing
+ Span opentracing.Span // tracing object
+ Syslog bool // write to StdOut and Syslog, not supported when tunneling
+ Trace bool // Hidden: Trace execution
+ Uri string // URI to API Service
+
+ Runroot string
+ StorageDriver string
+ StorageOpts []string
+}
+
+// DefaultSecurityOptions: getter for security options from configuration
+func (c PodmanConfig) DefaultSecurityOptions() []string {
+ securityOpts := []string{}
+ if c.Containers.SeccompProfile != "" && c.Containers.SeccompProfile != parse.SeccompDefaultPath {
+ securityOpts = append(securityOpts, fmt.Sprintf("seccomp=%s", c.Containers.SeccompProfile))
+ }
+ if apparmor.IsEnabled() && c.Containers.ApparmorProfile != "" {
+ securityOpts = append(securityOpts, fmt.Sprintf("apparmor=%s", c.Containers.ApparmorProfile))
+ }
+ if selinux.GetEnabled() && !c.Containers.EnableLabeling {
+ securityOpts = append(securityOpts, fmt.Sprintf("label=%s", selinux.DisableSecOpt()[0]))
+ }
+ return securityOpts
+}
+
+// DefaultSysctls
+func (c PodmanConfig) DefaultSysctls() []string {
+ return c.Containers.DefaultSysctls
+}
+
+func (c PodmanConfig) DefaultVolumes() []string {
+ return c.Containers.Volumes
+}
+
+func (c PodmanConfig) DefaultDevices() []string {
+ return c.Containers.Devices
+}
+
+func (c PodmanConfig) DefaultDNSServers() []string {
+ return c.Containers.DNSServers
+}
+
+func (c PodmanConfig) DefaultDNSSearches() []string {
+ return c.Containers.DNSSearches
+}
+
+func (c PodmanConfig) DefaultDNSOptions() []string {
+ return c.Containers.DNSOptions
+}
+
+func (c PodmanConfig) DefaultEnv() []string {
+ return c.Containers.Env
+}
+
+func (c PodmanConfig) DefaultInitPath() string {
+ return c.Containers.InitPath
+}
+
+func (c PodmanConfig) DefaultIPCNS() string {
+ return c.Containers.IPCNS
}
+
+func (c PodmanConfig) DefaultPidNS() string {
+ return c.Containers.PidNS
+}
+
+func (c PodmanConfig) DefaultNetNS() string {
+ if c.Containers.NetNS == "private" && rootless.IsRootless() {
+ return "slirp4netns"
+ }
+ return c.Containers.NetNS
+}
+
+func (c PodmanConfig) DefaultCgroupNS() string {
+ return c.Containers.CgroupNS
+}
+
+func (c PodmanConfig) DefaultUTSNS() string {
+ return c.Containers.UTSNS
+}
+
+func (c PodmanConfig) DefaultShmSize() string {
+ return c.Containers.ShmSize
+}
+
+func (c PodmanConfig) DefaultUlimits() []string {
+ return c.Containers.DefaultUlimits
+}
+
+func (c PodmanConfig) DefaultUserNS() string {
+ if v, found := os.LookupEnv("PODMAN_USERNS"); found {
+ return v
+ }
+ return c.Containers.UserNS
+}
+
+func (c PodmanConfig) DefaultPidsLimit() int64 {
+ if rootless.IsRootless() {
+ cgroup2, _ := cgroups.IsCgroup2UnifiedMode()
+ if cgroup2 {
+ return c.Containers.PidsLimit
+ }
+ }
+ return sysinfo.GetDefaultPidsLimit()
+}
+
+func (c PodmanConfig) DefaultPidsDescription() string {
+ return "Tune container pids limit (set 0 for unlimited)"
+}
+
+func (c PodmanConfig) DefaultDetachKeys() string {
+ return c.Engine.DetachKeys
+}
+
+// TODO: Remove in rootless support PR
+// // EngineOptions holds the environment for running the engines
+// type EngineOptions struct {
+// // Introduced with V2
+// Uri string
+// Identities []string
+// FlagSet *pflag.FlagSet
+// EngineMode EngineMode
+// CGroupUsage string
+//
+// // Introduced with V1
+// CGroupManager string // config.EngineConfig
+// CniConfigDir string // config.NetworkConfig.NetworkConfigDir
+// ConmonPath string // config.EngineConfig
+// DefaultMountsFile string // config.ContainersConfig
+// EventsBackend string // config.EngineConfig.EventsLogger
+// HooksDir []string // config.EngineConfig
+// MaxWorks int
+// Namespace string // config.EngineConfig
+// Root string //
+// Runroot string // config.EngineConfig.StorageConfigRunRootSet??
+// Runtime string // config.EngineConfig.OCIRuntime
+// StorageDriver string // config.EngineConfig.StorageConfigGraphDriverNameSet??
+// StorageOpts []string
+// Syslog bool
+// Trace bool
+// NetworkCmdPath string // config.EngineConfig
+//
+// Config string
+// CpuProfile string
+// LogLevel string
+// TmpDir string // config.EngineConfig
+//
+// RemoteUserName string // deprecated
+// RemoteHost string // deprecated
+// VarlinkAddress string // deprecated
+// ConnectionName string
+// RemoteConfigFilePath string
+// Port int // deprecated
+// IdentityFile string // deprecated
+// IgnoreHosts bool
+// }
+//
+// func NewEngineOptions(opts EngineOptions) (EngineOptions, error) {
+// ctnrCfg, err := config.Default()
+// if err != nil {
+// logrus.Error(err)
+// os.Exit(1)
+// }
+//
+// cgroupManager := ctnrCfg.Engine.CgroupManager
+// cgroupUsage := `Cgroup manager to use ("cgroupfs"|"systemd")`
+// cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
+// cniPluginDir := ctnrCfg.Network.CNIPluginDirs[0]
+//
+// cfg, err := config.NewConfig("")
+// if err != nil {
+// logrus.Errorf("Error loading container config %v\n", err)
+// os.Exit(1)
+// }
+// cfg.CheckCgroupsAndAdjustConfig()
+//
+// if rootless.IsRootless() {
+// if !cgroupv2 {
+// cgroupManager = ""
+// cgroupUsage = "Cgroup manager is not supported in rootless mode"
+// }
+// cniPluginDir = ""
+// }
+//
+// return EngineOptions{
+// CGroupManager: cgroupManager,
+// CGroupUsage: cgroupUsage,
+// CniConfigDir: cniPluginDir,
+// Config: opts.Config, // TODO: deprecate
+// ConmonPath: opts.ConmonPath,
+// ConnectionName: opts.ConnectionName,
+// CpuProfile: opts.CpuProfile,
+// DefaultMountsFile: ctnrCfg.Containers.DefaultMountsFile,
+// EngineMode: opts.EngineMode,
+// EventsBackend: ctnrCfg.Engine.EventsLogger,
+// FlagSet: opts.FlagSet, // TODO: deprecate
+// HooksDir: append(ctnrCfg.Engine.HooksDir[:0:0], ctnrCfg.Engine.HooksDir...),
+// Identities: append(opts.Identities[:0:0], opts.Identities...),
+// IdentityFile: opts.IdentityFile, // TODO: deprecate
+// IgnoreHosts: opts.IgnoreHosts,
+// LogLevel: opts.LogLevel,
+// MaxWorks: opts.MaxWorks,
+// Namespace: ctnrCfg.Engine.Namespace,
+// NetworkCmdPath: ctnrCfg.Engine.NetworkCmdPath,
+// Port: opts.Port,
+// RemoteConfigFilePath: opts.RemoteConfigFilePath,
+// RemoteHost: opts.RemoteHost, // TODO: deprecate
+// RemoteUserName: opts.RemoteUserName, // TODO: deprecate
+// Root: opts.Root,
+// Runroot: opts.Runroot,
+// Runtime: opts.Runtime,
+// StorageDriver: opts.StorageDriver,
+// StorageOpts: append(opts.StorageOpts[:0:0], opts.StorageOpts...),
+// Syslog: opts.Syslog,
+// TmpDir: opts.TmpDir,
+// Trace: opts.Trace,
+// Uri: opts.Uri,
+// VarlinkAddress: opts.VarlinkAddress,
+// }, nil
+// }
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 7e455b969..5fdb9a8a6 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -3,11 +3,13 @@ package entities
import (
"context"
+ "github.com/containers/common/pkg/config"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/specgen"
)
type ContainerEngine interface {
+ Config(ctx context.Context) (*config.Config, error)
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error)
@@ -17,9 +19,11 @@ type ContainerEngine interface {
ContainerExec(ctx context.Context, nameOrId string, options ExecOptions) (int, error)
ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error
+ ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error)
ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error)
ContainerList(ctx context.Context, options ContainerListOptions) ([]ListContainer, error)
+ ContainerMount(ctx context.Context, nameOrIds []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerLogs(ctx context.Context, containers []string, options ContainerLogsOptions) error
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
@@ -29,8 +33,10 @@ type ContainerEngine interface {
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, 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)
ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
+ Events(ctx context.Context, opts EventsOptions) error
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 16b96e9ef..3a051ab9b 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -2,9 +2,12 @@ package entities
import (
"context"
+
+ "github.com/containers/common/pkg/config"
)
type ImageEngine interface {
+ Config(ctx context.Context) (*config.Config, error)
Delete(ctx context.Context, nameOrId []string, opts ImageDeleteOptions) (*ImageDeleteReport, error)
Diff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error)
Exists(ctx context.Context, nameOrId string) (*BoolReport, error)
@@ -19,4 +22,5 @@ type ImageEngine interface {
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
+ Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, error)
}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index bc8a34c13..78ebb8805 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -2,6 +2,7 @@ package entities
import (
"net/url"
+ "time"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
@@ -99,12 +100,12 @@ type ImageDeleteReport struct {
type ImageHistoryOptions struct{}
type ImageHistoryLayer struct {
- ID string `json:"Id"`
- Created int64 `json:",omitempty"`
- CreatedBy string `json:",omitempty"`
- Tags []string `json:",omitempty"`
- Size int64 `json:",omitempty"`
- Comment string `json:",omitempty"`
+ ID string `json:"id"`
+ Created time.Time `json:"created,omitempty"`
+ CreatedBy string `json:",omitempty"`
+ Tags []string `json:"tags,omitempty"`
+ Size int64 `json:"size"`
+ Comment string `json:"comment,omitempty"`
}
type ImageHistoryReport struct {
@@ -181,6 +182,37 @@ type ImagePushOptions struct {
TLSVerify types.OptionalBool
}
+// ImageSearchOptions are the arguments for searching images.
+type ImageSearchOptions struct {
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile string
+ // Filters for the search results.
+ Filters []string
+ // Limit the number of results.
+ Limit int
+ // NoTrunc will not truncate the output.
+ NoTrunc bool
+ // TLSVerify to enable/disable HTTPS and certificate verification.
+ TLSVerify types.OptionalBool
+}
+
+// ImageSearchReport is the response from searching images.
+type ImageSearchReport struct {
+ // Index is the image index (e.g., "docker.io" or "quay.io")
+ Index string
+ // Name is the canoncical name of the image (e.g., "docker.io/library/alpine").
+ Name string
+ // Description of the image.
+ Description string
+ // Stars is the number of stars of the image.
+ Stars int
+ // Official indicates if it's an official image.
+ Official string
+ // Automated indicates if the image was created by an automated build.
+ Automated string
+}
+
type ImageListOptions struct {
All bool `json:"all" schema:"all"`
Filter []string `json:"Filter,omitempty"`
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index cd2e79961..9ca8ff43c 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -1,6 +1,7 @@
package entities
import (
+ "strings"
"time"
"github.com/containers/libpod/libpod"
@@ -121,7 +122,9 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
s.Hostname = p.Hostname
s.Labels = p.Labels
s.NoInfra = !p.Infra
- s.InfraCommand = []string{p.InfraCommand}
+ if len(p.InfraCommand) > 0 {
+ s.InfraCommand = strings.Split(p.InfraCommand, " ")
+ }
s.InfraImage = p.InfraImage
s.SharedNamespaces = p.Share
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index 7e35957f4..91ae00764 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -3,6 +3,7 @@ package entities
import (
"net"
+ "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/specgen"
"github.com/containers/storage/pkg/archive"
"github.com/cri-o/ocicni/pkg/ocicni"
@@ -62,3 +63,12 @@ type DiffOptions struct {
type DiffReport struct {
Changes []archive.Change
}
+
+type EventsOptions struct {
+ FromStart bool
+ EventChan chan *events.Event
+ Filter []string
+ Stream bool
+ Since string
+ Until string
+}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 7f8ec210b..f464df3ac 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -6,11 +6,13 @@ import (
"context"
"fmt"
"io/ioutil"
+ "os"
"strconv"
"strings"
"sync"
"github.com/containers/buildah"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/manifest"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
@@ -21,9 +23,11 @@ import (
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/infra/abi/terminal"
"github.com/containers/libpod/pkg/ps"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/signal"
"github.com/containers/libpod/pkg/specgen"
"github.com/containers/libpod/pkg/specgen/generate"
+ "github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -794,3 +798,104 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
}
return reports, nil
}
+
+func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
+ var reports []*entities.ContainerInitReport
+ ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, ctr := range ctrs {
+ report := entities.ContainerInitReport{Id: ctr.ID()}
+ report.Err = ctr.Init(ctx)
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
+ if os.Geteuid() != 0 {
+ if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
+ // Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
+ // of the mount command.
+ return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
+ }
+
+ became, ret, err := rootless.BecomeRootInUserNS("")
+ if err != nil {
+ return nil, err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ }
+ var reports []*entities.ContainerMountReport
+ ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, ctr := range ctrs {
+ report := entities.ContainerMountReport{Id: ctr.ID()}
+ report.Path, report.Err = ctr.Mount()
+ reports = append(reports, &report)
+ }
+ if len(reports) > 0 {
+ return reports, nil
+ }
+
+ // No containers were passed, so we send back what is mounted
+ ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, ctr := range ctrs {
+ mounted, path, err := ctr.Mounted()
+ if err != nil {
+ return nil, err
+ }
+
+ if mounted {
+ reports = append(reports, &entities.ContainerMountReport{
+ Id: ctr.ID(),
+ Name: ctr.Name(),
+ Path: path,
+ })
+ }
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
+ var reports []*entities.ContainerUnmountReport
+ ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, ctr := range ctrs {
+ state, err := ctr.State()
+ if err != nil {
+ logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
+ continue
+ }
+ if state == define.ContainerStateRunning {
+ logrus.Debugf("Error umounting container %s, is running", ctr.ID())
+ continue
+ }
+
+ report := entities.ContainerUnmountReport{Id: ctr.ID()}
+ if err := ctr.Unmount(options.Force); err != nil {
+ if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
+ logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
+ continue
+ }
+ report.Err = errors.Wrapf(err, "error unmounting container %s", ctr.ID())
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+// GetConfig returns a copy of the configuration used by the runtime
+func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
+ return ic.Libpod.GetConfig()
+}
diff --git a/pkg/domain/infra/abi/events.go b/pkg/domain/infra/abi/events.go
new file mode 100644
index 000000000..9540a5b96
--- /dev/null
+++ b/pkg/domain/infra/abi/events.go
@@ -0,0 +1,18 @@
+//+build ABISupport
+
+package abi
+
+import (
+ "context"
+
+ "github.com/containers/libpod/libpod/events"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/sirupsen/logrus"
+)
+
+func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptions) error {
+ readOpts := events.ReadOptions{FromStart: opts.FromStart, Stream: opts.Stream, Filters: opts.Filter, EventChannel: opts.EventChan, Since: opts.Since, Until: opts.Until}
+ err := ic.Libpod.Events(readOpts)
+ logrus.Error(err)
+ return err
+}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 24ee596be..9467c14d4 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -9,6 +9,7 @@ import (
"os"
"strings"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker"
dockerarchive "github.com/containers/image/v5/docker/archive"
"github.com/containers/image/v5/docker/reference"
@@ -45,7 +46,9 @@ func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entit
if err != nil {
return &report, errors.Wrapf(err, "unable to query local images")
}
-
+ if len(targets) == 0 {
+ return &report, nil
+ }
if len(targets) > 0 && len(targets) == len(previousTargets) {
return &report, errors.New("unable to delete all images; re-run the rmi command again.")
}
@@ -142,7 +145,7 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entiti
func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer {
l := entities.ImageHistoryLayer{}
l.ID = layer.ID
- l.Created = layer.Created.Unix()
+ l.Created = *layer.Created
l.CreatedBy = layer.CreatedBy
copy(l.Tags, layer.Tags)
l.Size = layer.Size
@@ -394,8 +397,10 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
if err != nil {
return nil, errors.Wrap(err, "image loaded but no additional tags were created")
}
- if err := newImage.TagImage(opts.Name); err != nil {
- return nil, errors.Wrapf(err, "error adding %q to image %q", opts.Name, newImage.InputName)
+ if len(opts.Name) > 0 {
+ if err := newImage.TagImage(fmt.Sprintf("%s:%s", opts.Name, opts.Tag)); err != nil {
+ return nil, errors.Wrapf(err, "error adding %q to image %q", opts.Name, newImage.InputName)
+ }
}
return &entities.ImageLoadReport{Name: name}, nil
}
@@ -423,3 +428,43 @@ func (ir *ImageEngine) Diff(_ context.Context, nameOrId string, _ entities.DiffO
}
return &entities.DiffReport{Changes: changes}, nil
}
+
+func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
+ filter, err := image.ParseSearchFilter(opts.Filters)
+ if err != nil {
+ return nil, err
+ }
+
+ searchOpts := image.SearchOptions{
+ Authfile: opts.Authfile,
+ Filter: *filter,
+ Limit: opts.Limit,
+ NoTrunc: opts.NoTrunc,
+ InsecureSkipTLSVerify: opts.TLSVerify,
+ }
+
+ searchResults, err := image.SearchImages(term, searchOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ // Convert from image.SearchResults to entities.ImageSearchReport. We don't
+ // want to leak any low-level packages into the remote client, which
+ // requires converting.
+ reports := make([]entities.ImageSearchReport, len(searchResults))
+ for i := range searchResults {
+ reports[i].Index = searchResults[i].Index
+ reports[i].Name = searchResults[i].Name
+ reports[i].Description = searchResults[i].Index
+ reports[i].Stars = searchResults[i].Stars
+ reports[i].Official = searchResults[i].Official
+ reports[i].Automated = searchResults[i].Automated
+ }
+
+ return reports, nil
+}
+
+// GetConfig returns a copy of the configuration used by the runtime
+func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
+ return ir.Libpod.GetConfig()
+}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index c3e5d59bc..bb637de3e 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -5,13 +5,13 @@ package abi
import (
"context"
- lpfilters "github.com/containers/libpod/libpod/filters"
-
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ lpfilters "github.com/containers/libpod/libpod/filters"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/signal"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/specgen/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -246,7 +246,7 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator()
opts.ToPodSpecGen(podSpec)
- pod, err := podSpec.MakePod(ic.Libpod)
+ pod, err := generate.MakePod(podSpec, ic.Libpod)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 2df11cc1b..10872144b 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -4,17 +4,28 @@ package abi
import (
"context"
+ "fmt"
+ "io/ioutil"
"net"
+ "os"
+ "strconv"
"strings"
+ "syscall"
+ "github.com/containers/common/pkg/config"
"github.com/containers/libpod/libpod/define"
api "github.com/containers/libpod/pkg/api/server"
+ "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/util"
iopodman "github.com/containers/libpod/pkg/varlink"
iopodmanAPI "github.com/containers/libpod/pkg/varlinkapi"
+ "github.com/containers/libpod/utils"
"github.com/containers/libpod/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
"github.com/varlink/go/varlink"
)
@@ -51,7 +62,6 @@ func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceO
}()
err = server.Serve()
- logrus.Debugf("%d/%d Active connections/Total connections\n", server.ActiveConnections, server.TotalConnections)
_ = listener.Close()
return err
}
@@ -89,3 +99,146 @@ func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.Servi
}
return nil
}
+
+func (ic *ContainerEngine) SetupRootless(cmd *cobra.Command) error {
+ // do it only after podman has already re-execed and running with uid==0.
+ if os.Geteuid() == 0 {
+ ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup()
+ if err != nil {
+ logrus.Warnf("Failed to detect the owner for the current cgroup: %v", err)
+ }
+ if !ownsCgroup {
+ conf, err := ic.Config(context.Background())
+ if err != nil {
+ return err
+ }
+ unitName := fmt.Sprintf("podman-%d.scope", os.Getpid())
+ if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil {
+ if conf.Engine.CgroupManager == config.SystemdCgroupsManager {
+ logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err)
+ } else {
+ logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err)
+ }
+ }
+ }
+ }
+
+ if !executeCommandInUserNS(cmd) {
+ return nil
+ }
+
+ pausePidPath, err := util.GetRootlessPauseProcessPidPath()
+ if err != nil {
+ return errors.Wrapf(err, "could not get pause process pid file path")
+ }
+
+ became, ret, err := rootless.TryJoinPauseProcess(pausePidPath)
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+
+ // if there is no pid file, try to join existing containers, and create a pause process.
+ ctrs, err := ic.Libpod.GetRunningContainers()
+ if err != nil {
+ logrus.WithError(err).Fatal("")
+ }
+
+ paths := []string{}
+ for _, ctr := range ctrs {
+ paths = append(paths, ctr.Config().ConmonPidFile)
+ }
+
+ became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
+ if err := movePauseProcessToScope(); err != nil {
+ conf, err := ic.Config(context.Background())
+ if err != nil {
+ return err
+ }
+ if conf.Engine.CgroupManager == config.SystemdCgroupsManager {
+ logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err)
+ } else {
+ logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err)
+ }
+ }
+ if err != nil {
+ logrus.WithError(err).Fatal("")
+ }
+ if became {
+ os.Exit(ret)
+ }
+ return nil
+}
+
+// Most podman commands when run in rootless mode, need to be executed in the
+// users usernamespace. This function is updated with a list of commands that
+// should NOT be run within the user namespace.
+func executeCommandInUserNS(cmd *cobra.Command) bool {
+ return os.Geteuid() == 0
+ // if os.Geteuid() == 0 {
+ // return false
+ // }
+ // switch cmd {
+ // case _migrateCommand,
+ // _mountCommand,
+ // _renumberCommand,
+ // _searchCommand,
+ // _versionCommand:
+ // return false
+ // }
+ // return true
+}
+
+func movePauseProcessToScope() error {
+ pausePidPath, err := util.GetRootlessPauseProcessPidPath()
+ if err != nil {
+ return errors.Wrapf(err, "could not get pause process pid file path")
+ }
+
+ data, err := ioutil.ReadFile(pausePidPath)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read pause pid file")
+ }
+ pid, err := strconv.ParseUint(string(data), 10, 0)
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse pid file %s", pausePidPath)
+ }
+
+ return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope")
+}
+
+func setRLimits() error { // nolint:deadcode,unused
+ rlimits := new(syscall.Rlimit)
+ rlimits.Cur = 1048576
+ rlimits.Max = 1048576
+ if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil {
+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil {
+ return errors.Wrapf(err, "error getting rlimits")
+ }
+ rlimits.Cur = rlimits.Max
+ if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil {
+ return errors.Wrapf(err, "error setting new rlimits")
+ }
+ }
+ return nil
+}
+
+func setUMask() { // nolint:deadcode,unused
+ // Be sure we can create directories with 0755 mode.
+ syscall.Umask(0022)
+}
+
+// checkInput can be used to verify any of the globalopt values
+func checkInput() error { // nolint:deadcode,unused
+ return nil
+}
+
+// func getCNIPluginsDir() string {
+// if rootless.IsRootless() {
+// return ""
+// }
+//
+// return registry.PodmanOptions.Network.CNIPluginDirs[0]
+// }
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index f11026571..0dbcf2ad2 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -12,7 +12,7 @@ import (
)
// NewContainerEngine factory provides a libpod runtime for container-related operations
-func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine, error) {
+func NewContainerEngine(facts entities.PodmanConfig) (entities.ContainerEngine, error) {
switch facts.EngineMode {
case entities.ABIMode:
r, err := NewLibpodRuntime(facts.FlagSet, facts)
@@ -25,7 +25,7 @@ func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine,
}
// NewContainerEngine factory provides a libpod runtime for image-related operations
-func NewImageEngine(facts entities.EngineOptions) (entities.ImageEngine, error) {
+func NewImageEngine(facts entities.PodmanConfig) (entities.ImageEngine, error) {
switch facts.EngineMode {
case entities.ABIMode:
r, err := NewLibpodImageRuntime(facts.FlagSet, facts)
diff --git a/pkg/domain/infra/runtime_image_proxy.go b/pkg/domain/infra/runtime_image_proxy.go
index befc66b9a..45c5425a3 100644
--- a/pkg/domain/infra/runtime_image_proxy.go
+++ b/pkg/domain/infra/runtime_image_proxy.go
@@ -12,7 +12,7 @@ import (
// ContainerEngine Image Proxy will be EOL'ed after podmanV2 is separated from libpod repo
-func NewLibpodImageRuntime(flags *pflag.FlagSet, opts entities.EngineOptions) (entities.ImageEngine, error) {
+func NewLibpodImageRuntime(flags *pflag.FlagSet, opts entities.PodmanConfig) (entities.ImageEngine, error) {
r, err := GetRuntime(context.Background(), flags, opts)
if err != nil {
return nil, err
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index d59759707..9cf374e2e 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -1,3 +1,5 @@
+// build: ABISupport
+
package infra
import (
@@ -22,68 +24,70 @@ type engineOpts struct {
migrate bool
noStore bool
withFDS bool
- flags entities.EngineOptions
+ config entities.PodmanConfig
}
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
-func GetRuntimeMigrate(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions, newRuntime string) (*libpod.Runtime, error) {
+func GetRuntimeMigrate(ctx context.Context, fs *flag.FlagSet, cfg entities.PodmanConfig, newRuntime string) (*libpod.Runtime, error) {
return getRuntime(ctx, fs, &engineOpts{
name: newRuntime,
renumber: false,
migrate: true,
noStore: false,
withFDS: true,
- flags: ef,
+ config: cfg,
})
}
// GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify
-func GetRuntimeDisableFDs(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) {
+func GetRuntimeDisableFDs(ctx context.Context, fs *flag.FlagSet, cfg entities.PodmanConfig) (*libpod.Runtime, error) {
return getRuntime(ctx, fs, &engineOpts{
renumber: false,
migrate: false,
noStore: false,
withFDS: false,
- flags: ef,
+ config: cfg,
})
}
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
-func GetRuntimeRenumber(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) {
+func GetRuntimeRenumber(ctx context.Context, fs *flag.FlagSet, cfg entities.PodmanConfig) (*libpod.Runtime, error) {
return getRuntime(ctx, fs, &engineOpts{
renumber: true,
migrate: false,
noStore: false,
withFDS: true,
- flags: ef,
+ config: cfg,
})
}
// GetRuntime generates a new libpod runtime configured by command line options
-func GetRuntime(ctx context.Context, flags *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) {
+func GetRuntime(ctx context.Context, flags *flag.FlagSet, cfg entities.PodmanConfig) (*libpod.Runtime, error) {
return getRuntime(ctx, flags, &engineOpts{
renumber: false,
migrate: false,
noStore: false,
withFDS: true,
- flags: ef,
+ config: cfg,
})
}
// GetRuntimeNoStore generates a new libpod runtime configured by command line options
-func GetRuntimeNoStore(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) {
+func GetRuntimeNoStore(ctx context.Context, fs *flag.FlagSet, cfg entities.PodmanConfig) (*libpod.Runtime, error) {
return getRuntime(ctx, fs, &engineOpts{
renumber: false,
migrate: false,
noStore: true,
withFDS: true,
- flags: ef,
+ config: cfg,
})
}
func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpod.Runtime, error) {
options := []libpod.RuntimeOption{}
storageOpts := storage.StoreOptions{}
+ cfg := opts.config
+
storageSet := false
uidmapFlag := fs.Lookup("uidmap")
@@ -109,25 +113,25 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
if fs.Changed("root") {
storageSet = true
- storageOpts.GraphRoot = opts.flags.Root
+ storageOpts.GraphRoot = cfg.Engine.StaticDir
}
if fs.Changed("runroot") {
storageSet = true
- storageOpts.RunRoot = opts.flags.Runroot
+ storageOpts.RunRoot = cfg.Runroot
}
if len(storageOpts.RunRoot) > 50 {
return nil, errors.New("the specified runroot is longer than 50 characters")
}
if fs.Changed("storage-driver") {
storageSet = true
- storageOpts.GraphDriverName = opts.flags.StorageDriver
+ storageOpts.GraphDriverName = cfg.StorageDriver
// Overriding the default storage driver caused GraphDriverOptions from storage.conf to be ignored
storageOpts.GraphDriverOptions = []string{}
}
// This should always be checked after storage-driver is checked
- if len(opts.flags.StorageOpts) > 0 {
+ if len(cfg.StorageOpts) > 0 {
storageSet = true
- storageOpts.GraphDriverOptions = opts.flags.StorageOpts
+ storageOpts.GraphDriverOptions = cfg.StorageOpts
}
if opts.migrate {
options = append(options, libpod.WithMigrate())
@@ -151,30 +155,30 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
// TODO CLI flags for image config?
// TODO CLI flag for signature policy?
- if len(opts.flags.Namespace) > 0 {
- options = append(options, libpod.WithNamespace(opts.flags.Namespace))
+ if len(cfg.Engine.Namespace) > 0 {
+ options = append(options, libpod.WithNamespace(cfg.Engine.Namespace))
}
if fs.Changed("runtime") {
- options = append(options, libpod.WithOCIRuntime(opts.flags.Runtime))
+ options = append(options, libpod.WithOCIRuntime(cfg.RuntimePath))
}
if fs.Changed("conmon") {
- options = append(options, libpod.WithConmonPath(opts.flags.ConmonPath))
+ options = append(options, libpod.WithConmonPath(cfg.ConmonPath))
}
if fs.Changed("tmpdir") {
- options = append(options, libpod.WithTmpDir(opts.flags.TmpDir))
+ options = append(options, libpod.WithTmpDir(cfg.Engine.TmpDir))
}
if fs.Changed("network-cmd-path") {
- options = append(options, libpod.WithNetworkCmdPath(opts.flags.NetworkCmdPath))
+ options = append(options, libpod.WithNetworkCmdPath(cfg.Engine.NetworkCmdPath))
}
if fs.Changed("events-backend") {
- options = append(options, libpod.WithEventsLogger(opts.flags.EventsBackend))
+ options = append(options, libpod.WithEventsLogger(cfg.Engine.EventsLogger))
}
if fs.Changed("cgroup-manager") {
- options = append(options, libpod.WithCgroupManager(opts.flags.CGroupManager))
+ options = append(options, libpod.WithCgroupManager(cfg.Engine.CgroupManager))
} else {
unified, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
@@ -189,13 +193,13 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
// TODO flag to set libpod tmp dir?
if fs.Changed("cni-config-dir") {
- options = append(options, libpod.WithCNIConfigDir(opts.flags.CniConfigDir))
+ options = append(options, libpod.WithCNIConfigDir(cfg.Network.NetworkConfigDir))
}
if fs.Changed("default-mounts-file") {
- options = append(options, libpod.WithDefaultMountsFile(opts.flags.DefaultMountsFile))
+ options = append(options, libpod.WithDefaultMountsFile(cfg.Containers.DefaultMountsFile))
}
if fs.Changed("hooks-dir") {
- options = append(options, libpod.WithHooksDir(opts.flags.HooksDir...))
+ options = append(options, libpod.WithHooksDir(cfg.Engine.HooksDir...))
}
// TODO flag to set CNI plugins dir?
diff --git a/pkg/domain/infra/runtime_proxy.go b/pkg/domain/infra/runtime_proxy.go
index 2e38c74b9..18f716ea0 100644
--- a/pkg/domain/infra/runtime_proxy.go
+++ b/pkg/domain/infra/runtime_proxy.go
@@ -12,7 +12,7 @@ import (
// ContainerEngine Proxy will be EOL'ed after podmanV2 is separated from libpod repo
-func NewLibpodRuntime(flags *flag.FlagSet, opts entities.EngineOptions) (entities.ContainerEngine, error) {
+func NewLibpodRuntime(flags *flag.FlagSet, opts entities.PodmanConfig) (entities.ContainerEngine, error) {
r, err := GetRuntime(context.Background(), flags, opts)
if err != nil {
return nil, err
diff --git a/pkg/domain/infra/runtime_tunnel.go b/pkg/domain/infra/runtime_tunnel.go
index dc04b4e53..129fdeb2c 100644
--- a/pkg/domain/infra/runtime_tunnel.go
+++ b/pkg/domain/infra/runtime_tunnel.go
@@ -11,7 +11,7 @@ import (
"github.com/containers/libpod/pkg/domain/infra/tunnel"
)
-func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine, error) {
+func NewContainerEngine(facts entities.PodmanConfig) (entities.ContainerEngine, error) {
switch facts.EngineMode {
case entities.ABIMode:
return nil, fmt.Errorf("direct runtime not supported")
@@ -23,7 +23,7 @@ func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine,
}
// NewImageEngine factory provides a libpod runtime for image-related operations
-func NewImageEngine(facts entities.EngineOptions) (entities.ImageEngine, error) {
+func NewImageEngine(facts entities.PodmanConfig) (entities.ImageEngine, error) {
switch facts.EngineMode {
case entities.ABIMode:
return nil, fmt.Errorf("direct image runtime not supported")
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 2bc3a1914..05b62efcf 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -5,6 +5,7 @@ import (
"io"
"os"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/bindings/containers"
@@ -242,7 +243,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
}
// narrow the list to running only
for _, c := range allCtrs {
- if c.ContainerState == define.ContainerStateRunning.String() {
+ if c.State == define.ContainerStateRunning.String() {
ctrs = append(ctrs, c)
}
}
@@ -276,7 +277,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
// narrow the list to exited only
for _, c := range allCtrs {
- if c.ContainerState == define.ContainerStateExited.String() {
+ if c.State == define.ContainerStateExited.String() {
ctrs = append(ctrs, c)
}
}
@@ -338,3 +339,31 @@ func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, _
func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) {
return nil, errors.New("not implemented")
}
+
+func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
+ var reports []*entities.ContainerInitReport
+ ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ for _, ctr := range ctrs {
+ err := containers.ContainerInit(ic.ClientCxt, ctr.ID)
+ reports = append(reports, &entities.ContainerInitReport{
+ Err: err,
+ Id: ctr.ID,
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
+ return nil, errors.New("mounting containers is not supported for remote clients")
+}
+
+func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
+ return nil, errors.New("unmounting containers is not supported for remote clients")
+}
+
+func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
+ return config.Default()
+}
diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go
new file mode 100644
index 000000000..46d88341a
--- /dev/null
+++ b/pkg/domain/infra/tunnel/events.go
@@ -0,0 +1,31 @@
+package tunnel
+
+import (
+ "context"
+ "strings"
+
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/bindings/system"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+)
+
+func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptions) error {
+ filters := make(map[string][]string)
+ if len(opts.Filter) > 0 {
+ for _, filter := range opts.Filter {
+ split := strings.Split(filter, "=")
+ if len(split) < 2 {
+ return errors.Errorf("invalid filter %q", filter)
+ }
+ filters[split[0]] = append(filters[split[0]], strings.Join(split[1:], "="))
+ }
+ }
+ binChan := make(chan handlers.Event)
+ go func() {
+ for e := range binChan {
+ opts.EventChan <- e.ToLibpodEvent()
+ }
+ }()
+ return system.Events(ic.ClientCxt, binChan, nil, &opts.Since, &opts.Until, filters)
+}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 4d7e45897..682d60d6a 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -30,7 +30,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
for _, id := range namesOrIds {
var found bool
for _, con := range c {
- if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.ContainerNames) {
+ if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.Names) {
cons = append(cons, con)
found = true
break
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 66abd7f47..7d40e0327 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
images "github.com/containers/libpod/pkg/bindings/images"
"github.com/containers/libpod/pkg/domain/entities"
@@ -250,3 +251,11 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrId string, _ entities.Dif
}
return &entities.DiffReport{Changes: changes}, nil
}
+
+func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
+ return images.Search(ir.ClientCxt, term, opts)
+}
+
+func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
+ return config.Default()
+}
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index 9217fa595..58fcc2c21 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -148,23 +148,23 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
}
ps := entities.ListContainer{
- Cmd: conConfig.Command,
- Created: conConfig.CreatedTime.Unix(),
- Exited: exited,
- ExitCode: exitCode,
- ExitedAt: exitedTime.Unix(),
- ID: conConfig.ID,
- Image: conConfig.RootfsImageName,
- IsInfra: conConfig.IsInfra,
- Labels: conConfig.Labels,
- Mounts: ctr.UserVolumes(),
- ContainerNames: []string{conConfig.Name},
- Pid: pid,
- Pod: conConfig.Pod,
- PortMappings: conConfig.PortMappings,
- ContainerSize: size,
- StartedAt: startedTime.Unix(),
- ContainerState: conState.String(),
+ Command: conConfig.Command,
+ Created: conConfig.CreatedTime.Unix(),
+ Exited: exited,
+ ExitCode: exitCode,
+ ExitedAt: exitedTime.Unix(),
+ ID: conConfig.ID,
+ Image: conConfig.RootfsImageName,
+ IsInfra: conConfig.IsInfra,
+ Labels: conConfig.Labels,
+ Mounts: ctr.UserVolumes(),
+ Names: []string{conConfig.Name},
+ Pid: pid,
+ Pod: conConfig.Pod,
+ Ports: conConfig.PortMappings,
+ Size: size,
+ StartedAt: startedTime.Unix(),
+ State: conState.String(),
}
if opts.Pod && len(conConfig.Pod) > 0 {
pod, err := rt.GetPod(conConfig.Pod)
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 6643bfbbf..da52a7217 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -288,6 +288,7 @@ static void __attribute__((constructor)) init()
char *cwd = getcwd (NULL, 0);
char uid_fmt[16];
char gid_fmt[16];
+ size_t len;
if (cwd == NULL)
{
@@ -295,13 +296,13 @@ static void __attribute__((constructor)) init()
_exit (EXIT_FAILURE);
}
- if (strlen (xdg_runtime_dir) >= PATH_MAX - strlen (suffix))
+ len = snprintf (path, PATH_MAX, "%s%s", xdg_runtime_dir, suffix);
+ if (len >= PATH_MAX)
{
fprintf (stderr, "invalid value for XDG_RUNTIME_DIR: %s", strerror (ENAMETOOLONG));
exit (EXIT_FAILURE);
}
- sprintf (path, "%s%s", xdg_runtime_dir, suffix);
fd = open (path, O_RDONLY);
if (fd < 0)
{
diff --git a/pkg/signal/signal_linux.go b/pkg/signal/signal_linux.go
index 76ab16ec7..e6e0f1ca1 100644
--- a/pkg/signal/signal_linux.go
+++ b/pkg/signal/signal_linux.go
@@ -129,14 +129,15 @@ func StopCatch(sigc chan os.Signal) {
// ParseSignalNameOrNumber translates a string to a valid syscall signal. Input
// can be a name or number representation i.e. "KILL" "9"
func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) {
- s, err := ParseSignal(rawSignal)
+ basename := strings.TrimPrefix(rawSignal, "-")
+ s, err := ParseSignal(basename)
if err == nil {
return s, nil
}
for k, v := range signalMap {
- if k == strings.ToUpper(rawSignal) {
+ if k == strings.ToUpper(basename) {
return v, nil
}
}
- return -1, fmt.Errorf("invalid signal: %s", rawSignal)
+ return -1, fmt.Errorf("invalid signal: %s", basename)
}
diff --git a/pkg/specgen/config_linux_nocgo.go b/pkg/specgen/config_linux_nocgo.go
deleted file mode 100644
index fc0c58c37..000000000
--- a/pkg/specgen/config_linux_nocgo.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build linux,!cgo
-
-package specgen
-
-import (
- spec "github.com/opencontainers/runtime-spec/specs-go"
-)
-
-func (s *SpecGenerator) getSeccompConfig(configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
- return nil, nil
-}
diff --git a/pkg/specgen/config_linux_cgo.go b/pkg/specgen/generate/config_linux_cgo.go
index ef6c6e951..b06ef5c9a 100644
--- a/pkg/specgen/config_linux_cgo.go
+++ b/pkg/specgen/generate/config_linux_cgo.go
@@ -1,6 +1,6 @@
// +build linux,cgo
-package specgen
+package generate
import (
"context"
@@ -8,13 +8,14 @@ import (
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/seccomp"
+ "github.com/containers/libpod/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
goSeccomp "github.com/seccomp/containers-golang"
"github.com/sirupsen/logrus"
)
-func (s *SpecGenerator) getSeccompConfig(configSpec *spec.Spec, img *image.Image) (*spec.LinuxSeccomp, error) {
+func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *image.Image) (*spec.LinuxSeccomp, error) {
var seccompConfig *spec.LinuxSeccomp
var err error
scp, err := seccomp.LookupPolicy(s.SeccompPolicy)
diff --git a/pkg/specgen/generate/config_linux_nocgo.go b/pkg/specgen/generate/config_linux_nocgo.go
new file mode 100644
index 000000000..fc8ed206d
--- /dev/null
+++ b/pkg/specgen/generate/config_linux_nocgo.go
@@ -0,0 +1,14 @@
+// +build linux,!cgo
+
+package generate
+
+import (
+ "errors"
+
+ "github.com/containers/libpod/pkg/specgen"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func (s *specgen.SpecGenerator) getSeccompConfig(configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
+ return nil, errors.New("not implemented")
+}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index aad59a861..264e0ff8e 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -40,7 +40,7 @@ func MakeContainer(rt *libpod.Runtime, s *specgen.SpecGenerator) (*libpod.Contai
options = append(options, libpod.WithRootFSFromImage(newImage.ID(), s.Image, s.RawImageName))
- runtimeSpec, err := s.ToOCISpec(rt, newImage)
+ runtimeSpec, err := SpecGenToOCI(s, rt, newImage)
if err != nil {
return nil, err
}
@@ -80,7 +80,15 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator) ([]lib
options = append(options, libpod.WithUserVolumes(destinations))
if len(s.Volumes) != 0 {
- options = append(options, libpod.WithNamedVolumes(s.Volumes))
+ var volumes []*libpod.ContainerNamedVolume
+ for _, v := range s.Volumes {
+ volumes = append(volumes, &libpod.ContainerNamedVolume{
+ Name: v.Name,
+ Dest: v.Dest,
+ Options: v.Options,
+ })
+ }
+ options = append(options, libpod.WithNamedVolumes(volumes))
}
if len(s.Command) != 0 {
@@ -115,7 +123,7 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator) ([]lib
options = append(options, libpod.WithPrivileged(s.Privileged))
// Get namespace related options
- namespaceOptions, err := s.GenerateNamespaceContainerOpts(rt)
+ namespaceOptions, err := GenerateNamespaceContainerOpts(s, rt)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
new file mode 100644
index 000000000..cdd7d86da
--- /dev/null
+++ b/pkg/specgen/generate/namespaces.go
@@ -0,0 +1,417 @@
+package generate
+
+import (
+ "os"
+
+ "github.com/containers/common/pkg/capabilities"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/specgen"
+ "github.com/cri-o/ocicni/pkg/ocicni"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func GenerateNamespaceContainerOpts(s *specgen.SpecGenerator, rt *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
+ var portBindings []ocicni.PortMapping
+ options := make([]libpod.CtrCreateOption, 0)
+
+ // Cgroups
+ switch {
+ case s.CgroupNS.IsPrivate():
+ ns := s.CgroupNS.Value
+ if _, err := os.Stat(ns); err != nil {
+ return nil, err
+ }
+ case s.CgroupNS.IsContainer():
+ connectedCtr, err := rt.LookupContainer(s.CgroupNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", s.CgroupNS.Value)
+ }
+ options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
+ // TODO
+ //default:
+ // return nil, errors.New("cgroup name only supports private and container")
+ }
+
+ if s.CgroupParent != "" {
+ options = append(options, libpod.WithCgroupParent(s.CgroupParent))
+ }
+
+ if s.CgroupsMode != "" {
+ options = append(options, libpod.WithCgroupsMode(s.CgroupsMode))
+ }
+
+ // ipc
+ switch {
+ case s.IpcNS.IsHost():
+ options = append(options, libpod.WithShmDir("/dev/shm"))
+ case s.IpcNS.IsContainer():
+ connectedCtr, err := rt.LookupContainer(s.IpcNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", s.IpcNS.Value)
+ }
+ options = append(options, libpod.WithIPCNSFrom(connectedCtr))
+ options = append(options, libpod.WithShmDir(connectedCtr.ShmDir()))
+ }
+
+ // pid
+ if s.PidNS.IsContainer() {
+ connectedCtr, err := rt.LookupContainer(s.PidNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", s.PidNS.Value)
+ }
+ options = append(options, libpod.WithPIDNSFrom(connectedCtr))
+ }
+
+ // uts
+ switch {
+ case s.UtsNS.IsPod():
+ connectedPod, err := rt.LookupPod(s.UtsNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "pod %q not found", s.UtsNS.Value)
+ }
+ options = append(options, libpod.WithUTSNSFromPod(connectedPod))
+ case s.UtsNS.IsContainer():
+ connectedCtr, err := rt.LookupContainer(s.UtsNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", s.UtsNS.Value)
+ }
+
+ options = append(options, libpod.WithUTSNSFrom(connectedCtr))
+ }
+
+ if s.UseImageHosts {
+ options = append(options, libpod.WithUseImageHosts())
+ } else if len(s.HostAdd) > 0 {
+ options = append(options, libpod.WithHosts(s.HostAdd))
+ }
+
+ // User
+
+ switch {
+ case s.UserNS.IsPath():
+ ns := s.UserNS.Value
+ if ns == "" {
+ return nil, errors.Errorf("invalid empty user-defined user namespace")
+ }
+ _, err := os.Stat(ns)
+ if err != nil {
+ return nil, err
+ }
+ if s.IDMappings != nil {
+ options = append(options, libpod.WithIDMappings(*s.IDMappings))
+ }
+ case s.UserNS.IsContainer():
+ connectedCtr, err := rt.LookupContainer(s.UserNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", s.UserNS.Value)
+ }
+ options = append(options, libpod.WithUserNSFrom(connectedCtr))
+ default:
+ if s.IDMappings != nil {
+ options = append(options, libpod.WithIDMappings(*s.IDMappings))
+ }
+ }
+
+ options = append(options, libpod.WithUser(s.User))
+ options = append(options, libpod.WithGroups(s.Groups))
+
+ if len(s.PortMappings) > 0 {
+ portBindings = s.PortMappings
+ }
+
+ switch {
+ case s.NetNS.IsPath():
+ ns := s.NetNS.Value
+ if ns == "" {
+ return nil, errors.Errorf("invalid empty user-defined network namespace")
+ }
+ _, err := os.Stat(ns)
+ if err != nil {
+ return nil, err
+ }
+ case s.NetNS.IsContainer():
+ connectedCtr, err := rt.LookupContainer(s.NetNS.Value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", s.NetNS.Value)
+ }
+ options = append(options, libpod.WithNetNSFrom(connectedCtr))
+ case !s.NetNS.IsHost() && s.NetNS.NSMode != specgen.NoNetwork:
+ postConfigureNetNS := !s.UserNS.IsHost()
+ options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(s.NetNS.NSMode), s.CNINetworks))
+ }
+
+ if len(s.DNSSearch) > 0 {
+ options = append(options, libpod.WithDNSSearch(s.DNSSearch))
+ }
+ if len(s.DNSServer) > 0 {
+ // TODO I'm not sure how we are going to handle this given the input
+ if len(s.DNSServer) == 1 { //&& strings.ToLower(s.DNSServer[0].) == "none" {
+ options = append(options, libpod.WithUseImageResolvConf())
+ } else {
+ var dnsServers []string
+ for _, d := range s.DNSServer {
+ dnsServers = append(dnsServers, d.String())
+ }
+ options = append(options, libpod.WithDNS(dnsServers))
+ }
+ }
+ if len(s.DNSOption) > 0 {
+ options = append(options, libpod.WithDNSOption(s.DNSOption))
+ }
+ if s.StaticIP != nil {
+ options = append(options, libpod.WithStaticIP(*s.StaticIP))
+ }
+
+ if s.StaticMAC != nil {
+ options = append(options, libpod.WithStaticMAC(*s.StaticMAC))
+ }
+ return options, nil
+}
+
+func pidConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
+ if s.PidNS.IsPath() {
+ return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value)
+ }
+ if s.PidNS.IsHost() {
+ return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
+ }
+ if s.PidNS.IsContainer() {
+ logrus.Debugf("using container %s pidmode", s.PidNS.Value)
+ }
+ if s.PidNS.IsPod() {
+ logrus.Debug("using pod pidmode")
+ }
+ return nil
+}
+
+func utsConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, runtime *libpod.Runtime) error {
+ hostname := s.Hostname
+ var err error
+ if hostname == "" {
+ switch {
+ case s.UtsNS.IsContainer():
+ utsCtr, err := runtime.LookupContainer(s.UtsNS.Value)
+ if err != nil {
+ return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", s.UtsNS.Value)
+ }
+ hostname = utsCtr.Hostname()
+ case s.NetNS.IsHost() || s.UtsNS.IsHost():
+ hostname, err = os.Hostname()
+ if err != nil {
+ return errors.Wrap(err, "unable to retrieve hostname of the host")
+ }
+ default:
+ logrus.Debug("No hostname set; container's hostname will default to runtime default")
+ }
+ }
+ g.RemoveHostname()
+ if s.Hostname != "" || !s.UtsNS.IsHost() {
+ // Set the hostname in the OCI configuration only
+ // if specified by the user or if we are creating
+ // a new UTS namespace.
+ g.SetHostname(hostname)
+ }
+ g.AddProcessEnv("HOSTNAME", hostname)
+
+ if s.UtsNS.IsPath() {
+ return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value)
+ }
+ if s.UtsNS.IsHost() {
+ return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
+ }
+ if s.UtsNS.IsContainer() {
+ logrus.Debugf("using container %s utsmode", s.UtsNS.Value)
+ }
+ return nil
+}
+
+func ipcConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
+ if s.IpcNS.IsPath() {
+ return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value)
+ }
+ if s.IpcNS.IsHost() {
+ return g.RemoveLinuxNamespace(s.IpcNS.Value)
+ }
+ if s.IpcNS.IsContainer() {
+ logrus.Debugf("Using container %s ipcmode", s.IpcNS.Value)
+ }
+ return nil
+}
+
+func cgroupConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
+ if s.CgroupNS.IsPath() {
+ return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value)
+ }
+ if s.CgroupNS.IsHost() {
+ return g.RemoveLinuxNamespace(s.CgroupNS.Value)
+ }
+ if s.CgroupNS.IsPrivate() {
+ return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
+ }
+ if s.CgroupNS.IsContainer() {
+ logrus.Debugf("Using container %s cgroup mode", s.CgroupNS.Value)
+ }
+ return nil
+}
+
+func networkConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
+ switch {
+ case s.NetNS.IsHost():
+ logrus.Debug("Using host netmode")
+ if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
+ return err
+ }
+
+ case s.NetNS.NSMode == specgen.NoNetwork:
+ logrus.Debug("Using none netmode")
+ case s.NetNS.NSMode == specgen.Bridge:
+ logrus.Debug("Using bridge netmode")
+ case s.NetNS.IsContainer():
+ logrus.Debugf("using container %s netmode", s.NetNS.Value)
+ case s.NetNS.IsPath():
+ logrus.Debug("Using ns netmode")
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
+ return err
+ }
+ case s.NetNS.IsPod():
+ logrus.Debug("Using pod netmode, unless pod is not sharing")
+ case s.NetNS.NSMode == specgen.Slirp:
+ logrus.Debug("Using slirp4netns netmode")
+ default:
+ return errors.Errorf("unknown network mode")
+ }
+
+ if g.Config.Annotations == nil {
+ g.Config.Annotations = make(map[string]string)
+ }
+
+ if s.PublishImagePorts {
+ g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
+ } else {
+ g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
+ }
+
+ return nil
+}
+
+func userConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) error {
+ if s.UserNS.IsPath() {
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), s.UserNS.Value); err != nil {
+ return err
+ }
+ // runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
+ g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
+ g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
+ }
+
+ if s.IDMappings != nil {
+ if (len(s.IDMappings.UIDMap) > 0 || len(s.IDMappings.GIDMap) > 0) && !s.UserNS.IsHost() {
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
+ return err
+ }
+ }
+ for _, uidmap := range s.IDMappings.UIDMap {
+ g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
+ }
+ for _, gidmap := range s.IDMappings.GIDMap {
+ g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
+ }
+ }
+ return nil
+}
+
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image) error {
+ // HANDLE CAPABILITIES
+ // NOTE: Must happen before SECCOMP
+ if s.Privileged {
+ g.SetupPrivileged(true)
+ }
+
+ useNotRoot := func(user string) bool {
+ if user == "" || user == "root" || user == "0" {
+ return false
+ }
+ return true
+ }
+ configSpec := g.Config
+ var err error
+ var caplist []string
+ bounding := configSpec.Process.Capabilities.Bounding
+ if useNotRoot(s.User) {
+ configSpec.Process.Capabilities.Bounding = caplist
+ }
+ caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, s.CapAdd, s.CapDrop)
+ if err != nil {
+ return err
+ }
+
+ configSpec.Process.Capabilities.Bounding = caplist
+ configSpec.Process.Capabilities.Permitted = caplist
+ configSpec.Process.Capabilities.Inheritable = caplist
+ configSpec.Process.Capabilities.Effective = caplist
+ configSpec.Process.Capabilities.Ambient = caplist
+ if useNotRoot(s.User) {
+ caplist, err = capabilities.MergeCapabilities(bounding, s.CapAdd, s.CapDrop)
+ if err != nil {
+ return err
+ }
+ }
+ configSpec.Process.Capabilities.Bounding = caplist
+
+ // HANDLE SECCOMP
+ if s.SeccompProfilePath != "unconfined" {
+ seccompConfig, err := getSeccompConfig(s, configSpec, newImage)
+ if err != nil {
+ return err
+ }
+ configSpec.Linux.Seccomp = seccompConfig
+ }
+
+ // Clear default Seccomp profile from Generator for privileged containers
+ if s.SeccompProfilePath == "unconfined" || s.Privileged {
+ configSpec.Linux.Seccomp = nil
+ }
+
+ g.SetRootReadonly(s.ReadOnlyFilesystem)
+ for sysctlKey, sysctlVal := range s.Sysctl {
+ g.AddLinuxSysctl(sysctlKey, sysctlVal)
+ }
+
+ return nil
+}
+
+// GetNamespaceOptions transforms a slice of kernel namespaces
+// into a slice of pod create options. Currently, not all
+// kernel namespaces are supported, and they will be returned in an error
+func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) {
+ var options []libpod.PodCreateOption
+ var erroredOptions []libpod.PodCreateOption
+ for _, toShare := range ns {
+ switch toShare {
+ case "cgroup":
+ options = append(options, libpod.WithPodCgroups())
+ case "net":
+ options = append(options, libpod.WithPodNet())
+ case "mnt":
+ return erroredOptions, errors.Errorf("Mount sharing functionality not supported on pod level")
+ case "pid":
+ options = append(options, libpod.WithPodPID())
+ case "user":
+ return erroredOptions, errors.Errorf("User sharing functionality not supported on pod level")
+ case "ipc":
+ options = append(options, libpod.WithPodIPC())
+ case "uts":
+ options = append(options, libpod.WithPodUTS())
+ case "":
+ case "none":
+ return erroredOptions, nil
+ default:
+ return erroredOptions, errors.Errorf("Invalid kernel namespace to share: %s. Options are: net, pid, ipc, uts or none", toShare)
+ }
+ }
+ return options, nil
+}
diff --git a/pkg/specgen/oci.go b/pkg/specgen/generate/oci.go
index 0756782b4..4bc4d2327 100644
--- a/pkg/specgen/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -1,4 +1,4 @@
-package specgen
+package generate
import (
"strings"
@@ -7,11 +7,12 @@ import (
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
createconfig "github.com/containers/libpod/pkg/spec"
+ "github.com/containers/libpod/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
)
-func (s *SpecGenerator) ToOCISpec(rt *libpod.Runtime, newImage *image.Image) (*spec.Spec, error) {
+func SpecGenToOCI(s *specgen.SpecGenerator, rt *libpod.Runtime, newImage *image.Image) (*spec.Spec, error) {
var (
inUserNS bool
)
@@ -183,32 +184,32 @@ func (s *SpecGenerator) ToOCISpec(rt *libpod.Runtime, newImage *image.Image) (*s
// NAMESPACES
- if err := s.pidConfigureGenerator(&g); err != nil {
+ if err := pidConfigureGenerator(s, &g); err != nil {
return nil, err
}
- if err := s.userConfigureGenerator(&g); err != nil {
+ if err := userConfigureGenerator(s, &g); err != nil {
return nil, err
}
- if err := s.networkConfigureGenerator(&g); err != nil {
+ if err := networkConfigureGenerator(s, &g); err != nil {
return nil, err
}
- if err := s.utsConfigureGenerator(&g, rt); err != nil {
+ if err := utsConfigureGenerator(s, &g, rt); err != nil {
return nil, err
}
- if err := s.ipcConfigureGenerator(&g); err != nil {
+ if err := ipcConfigureGenerator(s, &g); err != nil {
return nil, err
}
- if err := s.cgroupConfigureGenerator(&g); err != nil {
+ if err := cgroupConfigureGenerator(s, &g); err != nil {
return nil, err
}
configSpec := g.Config
- if err := s.securityConfigureGenerator(&g, newImage); err != nil {
+ if err := securityConfigureGenerator(s, &g, newImage); err != nil {
return nil, err
}
diff --git a/pkg/specgen/pod_create.go b/pkg/specgen/generate/pod_create.go
index 06aa24e22..292f9b155 100644
--- a/pkg/specgen/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -1,31 +1,31 @@
-package specgen
+package generate
import (
"context"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/specgen"
"github.com/sirupsen/logrus"
)
-func (p *PodSpecGenerator) MakePod(rt *libpod.Runtime) (*libpod.Pod, error) {
- if err := p.validate(); err != nil {
+func MakePod(p *specgen.PodSpecGenerator, rt *libpod.Runtime) (*libpod.Pod, error) {
+ if err := p.Validate(); err != nil {
return nil, err
}
- options, err := p.createPodOptions()
+ options, err := createPodOptions(p)
if err != nil {
return nil, err
}
return rt.NewPod(context.Background(), options...)
}
-func (p *PodSpecGenerator) createPodOptions() ([]libpod.PodCreateOption, error) {
+func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, error) {
var (
options []libpod.PodCreateOption
)
if !p.NoInfra {
options = append(options, libpod.WithInfraContainer())
- nsOptions, err := shared.GetNamespaceOptions(p.SharedNamespaces)
+ nsOptions, err := GetNamespaceOptions(p.SharedNamespaces)
if err != nil {
return nil, err
}
@@ -62,9 +62,9 @@ func (p *PodSpecGenerator) createPodOptions() ([]libpod.PodCreateOption, error)
options = append(options, libpod.WithPodUseImageResolvConf())
}
switch p.NetNS.NSMode {
- case Bridge:
+ case specgen.Bridge:
logrus.Debugf("Pod using default network mode")
- case Host:
+ case specgen.Host:
logrus.Debugf("Pod will use host networking")
options = append(options, libpod.WithPodHostNetwork())
default:
diff --git a/pkg/specgen/storage.go b/pkg/specgen/generate/storage.go
index 1b903f608..c9a36ed46 100644
--- a/pkg/specgen/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -1,4 +1,4 @@
-package specgen
+package generate
//nolint
@@ -8,9 +8,9 @@ import (
"path/filepath"
"strings"
- "github.com/containers/libpod/libpod"
-
"github.com/containers/buildah/pkg/parse"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/specgen"
"github.com/containers/libpod/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -38,7 +38,7 @@ var (
// TODO: Named volume options - should we default to rprivate? It bakes into a
// bind mount under the hood...
// TODO: handle options parsing/processing via containers/storage/pkg/mount
-func (s *SpecGenerator) parseVolumes(mounts, volMounts, tmpMounts []string) error { //nolint
+func parseVolumes(s *specgen.SpecGenerator, mounts, volMounts, tmpMounts []string) error { //nolint
// TODO this needs to come from the image and erquires a runtime
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index 2a7bb3495..2ef5bc229 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -1,16 +1,7 @@
package specgen
import (
- "os"
-
- "github.com/containers/common/pkg/capabilities"
- "github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/image"
- "github.com/cri-o/ocicni/pkg/ocicni"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
type NamespaceMode string
@@ -105,373 +96,3 @@ func (n *Namespace) validate() error {
}
return nil
}
-
-func (s *SpecGenerator) GenerateNamespaceContainerOpts(rt *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
- var portBindings []ocicni.PortMapping
- options := make([]libpod.CtrCreateOption, 0)
-
- // Cgroups
- switch {
- case s.CgroupNS.IsPrivate():
- ns := s.CgroupNS.Value
- if _, err := os.Stat(ns); err != nil {
- return nil, err
- }
- case s.CgroupNS.IsContainer():
- connectedCtr, err := rt.LookupContainer(s.CgroupNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", s.CgroupNS.Value)
- }
- options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
- // TODO
- //default:
- // return nil, errors.New("cgroup name only supports private and container")
- }
-
- if s.CgroupParent != "" {
- options = append(options, libpod.WithCgroupParent(s.CgroupParent))
- }
-
- if s.CgroupsMode != "" {
- options = append(options, libpod.WithCgroupsMode(s.CgroupsMode))
- }
-
- // ipc
- switch {
- case s.IpcNS.IsHost():
- options = append(options, libpod.WithShmDir("/dev/shm"))
- case s.IpcNS.IsContainer():
- connectedCtr, err := rt.LookupContainer(s.IpcNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", s.IpcNS.Value)
- }
- options = append(options, libpod.WithIPCNSFrom(connectedCtr))
- options = append(options, libpod.WithShmDir(connectedCtr.ShmDir()))
- }
-
- // pid
- if s.PidNS.IsContainer() {
- connectedCtr, err := rt.LookupContainer(s.PidNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", s.PidNS.Value)
- }
- options = append(options, libpod.WithPIDNSFrom(connectedCtr))
- }
-
- // uts
- switch {
- case s.UtsNS.IsPod():
- connectedPod, err := rt.LookupPod(s.UtsNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "pod %q not found", s.UtsNS.Value)
- }
- options = append(options, libpod.WithUTSNSFromPod(connectedPod))
- case s.UtsNS.IsContainer():
- connectedCtr, err := rt.LookupContainer(s.UtsNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", s.UtsNS.Value)
- }
-
- options = append(options, libpod.WithUTSNSFrom(connectedCtr))
- }
-
- if s.UseImageHosts {
- options = append(options, libpod.WithUseImageHosts())
- } else if len(s.HostAdd) > 0 {
- options = append(options, libpod.WithHosts(s.HostAdd))
- }
-
- // User
-
- switch {
- case s.UserNS.IsPath():
- ns := s.UserNS.Value
- if ns == "" {
- return nil, errors.Errorf("invalid empty user-defined user namespace")
- }
- _, err := os.Stat(ns)
- if err != nil {
- return nil, err
- }
- if s.IDMappings != nil {
- options = append(options, libpod.WithIDMappings(*s.IDMappings))
- }
- case s.UserNS.IsContainer():
- connectedCtr, err := rt.LookupContainer(s.UserNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", s.UserNS.Value)
- }
- options = append(options, libpod.WithUserNSFrom(connectedCtr))
- default:
- if s.IDMappings != nil {
- options = append(options, libpod.WithIDMappings(*s.IDMappings))
- }
- }
-
- options = append(options, libpod.WithUser(s.User))
- options = append(options, libpod.WithGroups(s.Groups))
-
- if len(s.PortMappings) > 0 {
- portBindings = s.PortMappings
- }
-
- switch {
- case s.NetNS.IsPath():
- ns := s.NetNS.Value
- if ns == "" {
- return nil, errors.Errorf("invalid empty user-defined network namespace")
- }
- _, err := os.Stat(ns)
- if err != nil {
- return nil, err
- }
- case s.NetNS.IsContainer():
- connectedCtr, err := rt.LookupContainer(s.NetNS.Value)
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", s.NetNS.Value)
- }
- options = append(options, libpod.WithNetNSFrom(connectedCtr))
- case !s.NetNS.IsHost() && s.NetNS.NSMode != NoNetwork:
- postConfigureNetNS := !s.UserNS.IsHost()
- options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(s.NetNS.NSMode), s.CNINetworks))
- }
-
- if len(s.DNSSearch) > 0 {
- options = append(options, libpod.WithDNSSearch(s.DNSSearch))
- }
- if len(s.DNSServer) > 0 {
- // TODO I'm not sure how we are going to handle this given the input
- if len(s.DNSServer) == 1 { //&& strings.ToLower(s.DNSServer[0].) == "none" {
- options = append(options, libpod.WithUseImageResolvConf())
- } else {
- var dnsServers []string
- for _, d := range s.DNSServer {
- dnsServers = append(dnsServers, d.String())
- }
- options = append(options, libpod.WithDNS(dnsServers))
- }
- }
- if len(s.DNSOption) > 0 {
- options = append(options, libpod.WithDNSOption(s.DNSOption))
- }
- if s.StaticIP != nil {
- options = append(options, libpod.WithStaticIP(*s.StaticIP))
- }
-
- if s.StaticMAC != nil {
- options = append(options, libpod.WithStaticMAC(*s.StaticMAC))
- }
- return options, nil
-}
-
-func (s *SpecGenerator) pidConfigureGenerator(g *generate.Generator) error {
- if s.PidNS.IsPath() {
- return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value)
- }
- if s.PidNS.IsHost() {
- return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
- }
- if s.PidNS.IsContainer() {
- logrus.Debugf("using container %s pidmode", s.PidNS.Value)
- }
- if s.PidNS.IsPod() {
- logrus.Debug("using pod pidmode")
- }
- return nil
-}
-
-func (s *SpecGenerator) utsConfigureGenerator(g *generate.Generator, runtime *libpod.Runtime) error {
- hostname := s.Hostname
- var err error
- if hostname == "" {
- switch {
- case s.UtsNS.IsContainer():
- utsCtr, err := runtime.LookupContainer(s.UtsNS.Value)
- if err != nil {
- return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", s.UtsNS.Value)
- }
- hostname = utsCtr.Hostname()
- case s.NetNS.IsHost() || s.UtsNS.IsHost():
- hostname, err = os.Hostname()
- if err != nil {
- return errors.Wrap(err, "unable to retrieve hostname of the host")
- }
- default:
- logrus.Debug("No hostname set; container's hostname will default to runtime default")
- }
- }
- g.RemoveHostname()
- if s.Hostname != "" || !s.UtsNS.IsHost() {
- // Set the hostname in the OCI configuration only
- // if specified by the user or if we are creating
- // a new UTS namespace.
- g.SetHostname(hostname)
- }
- g.AddProcessEnv("HOSTNAME", hostname)
-
- if s.UtsNS.IsPath() {
- return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value)
- }
- if s.UtsNS.IsHost() {
- return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
- }
- if s.UtsNS.IsContainer() {
- logrus.Debugf("using container %s utsmode", s.UtsNS.Value)
- }
- return nil
-}
-
-func (s *SpecGenerator) ipcConfigureGenerator(g *generate.Generator) error {
- if s.IpcNS.IsPath() {
- return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value)
- }
- if s.IpcNS.IsHost() {
- return g.RemoveLinuxNamespace(s.IpcNS.Value)
- }
- if s.IpcNS.IsContainer() {
- logrus.Debugf("Using container %s ipcmode", s.IpcNS.Value)
- }
- return nil
-}
-
-func (s *SpecGenerator) cgroupConfigureGenerator(g *generate.Generator) error {
- if s.CgroupNS.IsPath() {
- return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value)
- }
- if s.CgroupNS.IsHost() {
- return g.RemoveLinuxNamespace(s.CgroupNS.Value)
- }
- if s.CgroupNS.IsPrivate() {
- return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
- }
- if s.CgroupNS.IsContainer() {
- logrus.Debugf("Using container %s cgroup mode", s.CgroupNS.Value)
- }
- return nil
-}
-
-func (s *SpecGenerator) networkConfigureGenerator(g *generate.Generator) error {
- switch {
- case s.NetNS.IsHost():
- logrus.Debug("Using host netmode")
- if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
- return err
- }
-
- case s.NetNS.NSMode == NoNetwork:
- logrus.Debug("Using none netmode")
- case s.NetNS.NSMode == Bridge:
- logrus.Debug("Using bridge netmode")
- case s.NetNS.IsContainer():
- logrus.Debugf("using container %s netmode", s.NetNS.Value)
- case s.NetNS.IsPath():
- logrus.Debug("Using ns netmode")
- if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
- return err
- }
- case s.NetNS.IsPod():
- logrus.Debug("Using pod netmode, unless pod is not sharing")
- case s.NetNS.NSMode == Slirp:
- logrus.Debug("Using slirp4netns netmode")
- default:
- return errors.Errorf("unknown network mode")
- }
-
- if g.Config.Annotations == nil {
- g.Config.Annotations = make(map[string]string)
- }
-
- if s.PublishImagePorts {
- g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
- } else {
- g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
- }
-
- return nil
-}
-
-func (s *SpecGenerator) userConfigureGenerator(g *generate.Generator) error {
- if s.UserNS.IsPath() {
- if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), s.UserNS.Value); err != nil {
- return err
- }
- // runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
- g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
- g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
- }
-
- if s.IDMappings != nil {
- if (len(s.IDMappings.UIDMap) > 0 || len(s.IDMappings.GIDMap) > 0) && !s.UserNS.IsHost() {
- if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
- return err
- }
- }
- for _, uidmap := range s.IDMappings.UIDMap {
- g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
- }
- for _, gidmap := range s.IDMappings.GIDMap {
- g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
- }
- }
- return nil
-}
-
-func (s *SpecGenerator) securityConfigureGenerator(g *generate.Generator, newImage *image.Image) error {
- // HANDLE CAPABILITIES
- // NOTE: Must happen before SECCOMP
- if s.Privileged {
- g.SetupPrivileged(true)
- }
-
- useNotRoot := func(user string) bool {
- if user == "" || user == "root" || user == "0" {
- return false
- }
- return true
- }
- configSpec := g.Config
- var err error
- var caplist []string
- bounding := configSpec.Process.Capabilities.Bounding
- if useNotRoot(s.User) {
- configSpec.Process.Capabilities.Bounding = caplist
- }
- caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, s.CapAdd, s.CapDrop)
- if err != nil {
- return err
- }
-
- configSpec.Process.Capabilities.Bounding = caplist
- configSpec.Process.Capabilities.Permitted = caplist
- configSpec.Process.Capabilities.Inheritable = caplist
- configSpec.Process.Capabilities.Effective = caplist
- configSpec.Process.Capabilities.Ambient = caplist
- if useNotRoot(s.User) {
- caplist, err = capabilities.MergeCapabilities(bounding, s.CapAdd, s.CapDrop)
- if err != nil {
- return err
- }
- }
- configSpec.Process.Capabilities.Bounding = caplist
-
- // HANDLE SECCOMP
- if s.SeccompProfilePath != "unconfined" {
- seccompConfig, err := s.getSeccompConfig(configSpec, newImage)
- if err != nil {
- return err
- }
- configSpec.Linux.Seccomp = seccompConfig
- }
-
- // Clear default Seccomp profile from Generator for privileged containers
- if s.SeccompProfilePath == "unconfined" || s.Privileged {
- configSpec.Linux.Seccomp = nil
- }
-
- g.SetRootReadonly(s.ReadOnlyFilesystem)
- for sysctlKey, sysctlVal := range s.Sysctl {
- g.AddLinuxSysctl(sysctlKey, sysctlVal)
- }
-
- return nil
-}
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index 50309f096..9e9659fa9 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -15,7 +15,8 @@ func exclusivePodOptions(opt1, opt2 string) error {
return errors.Wrapf(ErrInvalidPodSpecConfig, "%s and %s are mutually exclusive pod options", opt1, opt2)
}
-func (p *PodSpecGenerator) validate() error {
+// Validate verifies the input is valid
+func (p *PodSpecGenerator) Validate() error {
// PodBasicConfig
if p.NoInfra {
if len(p.InfraCommand) > 0 {
@@ -25,7 +26,7 @@ func (p *PodSpecGenerator) validate() error {
return exclusivePodOptions("NoInfra", "InfraImage")
}
if len(p.SharedNamespaces) > 0 {
- return exclusivePodOptions("NoInfo", "SharedNamespaces")
+ return exclusivePodOptions("NoInfra", "SharedNamespaces")
}
}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 2e6dd9c1d..8482ef2c9 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -4,8 +4,6 @@ import (
"net"
"syscall"
- "github.com/containers/libpod/libpod"
-
"github.com/containers/image/v5/manifest"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
@@ -174,7 +172,7 @@ type ContainerStorageConfig struct {
// These will supersede Image Volumes and VolumesFrom volumes where
// there are conflicts.
// Optional.
- Volumes []*libpod.ContainerNamedVolume `json:"volumes,omitempty"`
+ Volumes []*Volumes `json:"volumes,omitempty"`
// Devices are devices that will be added to the container.
// Optional.
Devices []spec.LinuxDevice `json:"devices,omitempty"`
@@ -403,6 +401,13 @@ type SpecGenerator struct {
ContainerHealthCheckConfig
}
+// Volumes is a temporary struct to hold input from the User
+type Volumes struct {
+ Name string
+ Dest string
+ Options []string
+}
+
// NewSpecGenerator returns a SpecGenerator struct given one of two mandatory inputs
func NewSpecGenerator(image string) *SpecGenerator {
networkConfig := ContainerNetworkConfig{
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 372c7c53b..1051ed311 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -516,6 +516,8 @@ func ParseInputTime(inputTime string) (time.Time, error) {
}
// GetGlobalOpts checks all global flags and generates the command string
+// FIXME: Port input to config.Config
+// TODO: Is there a "better" way to reverse values to flags? This seems brittle.
func GetGlobalOpts(c *cliconfig.RunlabelValues) string {
globalFlags := map[string]bool{
"cgroup-manager": true, "cni-config-dir": true, "conmon": true, "default-mounts-file": true,