diff options
Diffstat (limited to 'pkg')
45 files changed, 728 insertions, 390 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 08e19edb8..a5242270e 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -19,13 +19,13 @@ import ( "github.com/containers/image/v5/manifest" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/cmd/podman/shared/parse" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/libpod/logs" "github.com/containers/libpod/pkg/adapter/shortcuts" + envLib "github.com/containers/libpod/pkg/env" "github.com/containers/libpod/pkg/systemd/generate" "github.com/containers/storage" "github.com/pkg/errors" @@ -987,9 +987,20 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal // Validate given environment variables env := map[string]string{} - if err := parse.ReadKVStrings(env, cli.EnvFile, cli.Env); err != nil { - return ec, errors.Wrapf(err, "unable to process environment variables") + if len(cli.EnvFile) > 0 { + for _, f := range cli.EnvFile { + fileEnv, err := envLib.ParseFile(f) + if err != nil { + return ec, err + } + env = envLib.Join(env, fileEnv) + } } + cliEnv, err := envLib.ParseSlice(cli.Env) + if err != nil { + return ec, errors.Wrap(err, "error parsing environment variables") + } + env = envLib.Join(env, cliEnv) streams := new(libpod.AttachStreams) streams.OutputStream = os.Stdout @@ -1101,6 +1112,15 @@ func (r *LocalRuntime) CleanupContainers(ctx context.Context, cli *cliconfig.Cle } else { failures[ctr.ID()] = err } + + if cli.RemoveImage { + _, imageName := ctr.Image() + if err := removeContainerImage(ctx, ctr, r); err != nil { + failures[imageName] = err + } else { + ok = append(ok, imageName) + } + } } return ok, failures, nil } @@ -1120,6 +1140,16 @@ func cleanupContainer(ctx context.Context, ctr *libpod.Container, runtime *Local return nil } +func removeContainerImage(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error { + _, imageName := ctr.Image() + ctrImage, err := runtime.NewImageFromLocal(imageName) + if err != nil { + return err + } + _, err = runtime.RemoveImage(ctx, ctrImage, false) + return err +} + // Port displays port information about existing containers func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) { var ( diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 60ee3cb2d..32a84b60d 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -15,11 +15,11 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/cmd/podman/shared/parse" iopodman "github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/logs" + envLib "github.com/containers/libpod/pkg/env" "github.com/containers/libpod/pkg/varlinkapi/virtwriter" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/docker/pkg/term" @@ -1025,16 +1025,11 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal ) // default invalid command exit code // Validate given environment variables - env := map[string]string{} - if err := parse.ReadKVStrings(env, []string{}, cli.Env); err != nil { - return -1, errors.Wrapf(err, "Exec unable to process environment variables") - } - - // Build env slice of key=value strings for Exec - envs := []string{} - for k, v := range env { - envs = append(envs, fmt.Sprintf("%s=%s", k, v)) + cliEnv, err := envLib.ParseSlice(cli.Env) + if err != nil { + return 0, errors.Wrap(err, "error parsing environment variables") } + envs := envLib.Slice(cliEnv) resize := make(chan remotecommand.TerminalSize, 5) haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 0d9fa7210..dc856cc8d 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -22,6 +22,7 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter/shortcuts" ann "github.com/containers/libpod/pkg/annotations" + envLib "github.com/containers/libpod/pkg/env" ns "github.com/containers/libpod/pkg/namespaces" createconfig "github.com/containers/libpod/pkg/spec" "github.com/containers/libpod/pkg/util" @@ -916,9 +917,6 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.User = userConfig containerConfig.Security = securityConfig - // Set default environment variables and incorporate data from image, if necessary - envs := shared.EnvVariablesFromData(imageData) - annotations := make(map[string]string) if infraID != "" { annotations[ann.SandboxID] = infraID @@ -927,6 +925,14 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.Annotations = annotations // Environment Variables + envs := map[string]string{} + if imageData != nil { + imageEnv, err := envLib.ParseSlice(imageData.Config.Env) + if err != nil { + return nil, errors.Wrap(err, "error parsing image environment variables") + } + envs = imageEnv + } for _, e := range containerYAML.Env { envs[e.Name] = e.Value } diff --git a/pkg/api/handlers/containers.go b/pkg/api/handlers/containers.go index ee080e794..1256256fd 100644 --- a/pkg/api/handlers/containers.go +++ b/pkg/api/handlers/containers.go @@ -2,12 +2,12 @@ package handlers import ( "fmt" - "github.com/docker/docker/api/types" "net/http" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/api/handlers/utils" + "github.com/docker/docker/api/types" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -72,7 +72,6 @@ func UnpauseContainer(w http.ResponseWriter, r *http.Request) { return } - // the api does not error if the Container is already paused, so just into it if err := con.Unpause(); err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/generic/containers.go b/pkg/api/handlers/generic/containers.go index ab587ded4..b8460702c 100644 --- a/pkg/api/handlers/generic/containers.go +++ b/pkg/api/handlers/generic/containers.go @@ -57,6 +57,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { }{ // override any golang type defaults } + 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 @@ -85,7 +86,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { var list = make([]*handlers.Container, len(containers)) for i, ctnr := range containers { - api, err := handlers.LibpodToContainer(ctnr, infoData) + api, err := handlers.LibpodToContainer(ctnr, infoData, query.Size) if err != nil { utils.InternalServerError(w, err) return @@ -97,6 +98,17 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { func GetContainer(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) + decoder := r.Context().Value("decoder").(*schema.Decoder) + query := struct { + Size bool `schema:"size"` + }{ + // override any golang type defaults + } + + 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 + } name := utils.GetName(r) ctnr, err := runtime.LookupContainer(name) @@ -104,7 +116,7 @@ func GetContainer(w http.ResponseWriter, r *http.Request) { utils.ContainerNotFound(w, name, err) return } - api, err := handlers.LibpodToContainerJSON(ctnr) + api, err := handlers.LibpodToContainerJSON(ctnr, query.Size) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/generic/images.go b/pkg/api/handlers/generic/images.go index 1ced499d9..078896834 100644 --- a/pkg/api/handlers/generic/images.go +++ b/pkg/api/handlers/generic/images.go @@ -90,7 +90,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { }) } - //FIXME/TODO to do this exacty correct, pruneimages needs to return idrs and space-reclaimed, then we are golden + //FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden ipr := types.ImagesPruneReport{ ImagesDeleted: idr, SpaceReclaimed: 1, // TODO we cannot supply this right now @@ -305,7 +305,7 @@ func GetImages(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images")) return } - var summaries = make([]*handlers.ImageSummary, len(images)+1) + var summaries = make([]*handlers.ImageSummary, len(images)) for j, img := range images { is, err := handlers.ImageToImageSummary(img) if err != nil { diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index e8dc5bde2..ee697b6b7 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -181,7 +181,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) { } // TODO we need to implement a pod.State/Status in libpod internal so libpod api - // users dont have to run through all containers. + // users don't have to run through all containers. podContainers, err := pod.AllContainers() if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) @@ -227,7 +227,7 @@ func PodStart(w http.ResponseWriter, r *http.Request) { } // TODO we need to implement a pod.State/Status in libpod internal so libpod api - // users dont have to run through all containers. + // users don't have to run through all containers. podContainers, err := pod.AllContainers() if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index 2930a9567..2e429dc58 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -347,7 +347,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI } -func LibpodToContainer(l *libpod.Container, infoData []define.InfoData) (*Container, error) { +func LibpodToContainer(l *libpod.Container, infoData []define.InfoData, sz bool) (*Container, error) { imageId, imageName := l.Image() var ( @@ -360,11 +360,18 @@ func LibpodToContainer(l *libpod.Container, infoData []define.InfoData) (*Contai if state, err = l.State(); err != nil { return nil, err } - if sizeRW, err = l.RWSize(); err != nil { - return nil, err + stateStr := state.String() + if stateStr == "configured" { + stateStr = "created" } - if sizeRootFs, err = l.RootFsSize(); err != nil { - return nil, err + + if sz { + if sizeRW, err = l.RWSize(); err != nil { + return nil, err + } + if sizeRootFs, err = l.RootFsSize(); err != nil { + return nil, err + } } return &Container{docker.Container{ @@ -378,7 +385,7 @@ func LibpodToContainer(l *libpod.Container, infoData []define.InfoData) (*Contai SizeRw: sizeRW, SizeRootFs: sizeRootFs, Labels: l.Labels(), - State: string(state), + State: stateStr, Status: "", HostConfig: struct { NetworkMode string `json:",omitempty"` @@ -391,9 +398,9 @@ func LibpodToContainer(l *libpod.Container, infoData []define.InfoData) (*Contai }, nil } -func LibpodToContainerJSON(l *libpod.Container) (*docker.ContainerJSON, error) { +func LibpodToContainerJSON(l *libpod.Container, sz bool) (*docker.ContainerJSON, error) { _, imageName := l.Image() - inspect, err := l.Inspect(true) + inspect, err := l.Inspect(sz) if err != nil { return nil, err } diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go index 44bcc794c..32b8c5b0a 100644 --- a/pkg/api/handlers/utils/handler.go +++ b/pkg/api/handlers/utils/handler.go @@ -3,7 +3,6 @@ package utils import ( "encoding/json" "fmt" - "github.com/pkg/errors" "io" "net/http" "net/url" @@ -11,6 +10,7 @@ import ( "strings" "github.com/gorilla/mux" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) diff --git a/pkg/api/server/register_auth.go b/pkg/api/server/register_auth.go index 8db131153..7e51c2b63 100644 --- a/pkg/api/server/register_auth.go +++ b/pkg/api/server/register_auth.go @@ -7,5 +7,7 @@ import ( func (s *APIServer) registerAuthHandlers(r *mux.Router) error { r.Handle(VersionedPath("/auth"), s.APIHandler(handlers.UnsupportedHandler)) + // Added non version path to URI to support docker non versioned paths + r.Handle("/auth", s.APIHandler(handlers.UnsupportedHandler)) return nil } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index 6aad7ff88..a87e8eaee 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -34,6 +34,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/create"), s.APIHandler(generic.CreateContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/create", s.APIHandler(generic.CreateContainer)).Methods(http.MethodPost) // swagger:operation GET /containers/json compat listContainers // --- // tags: @@ -84,6 +86,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/json"), s.APIHandler(generic.ListContainers)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/json", s.APIHandler(generic.ListContainers)).Methods(http.MethodGet) // swagger:operation POST /containers/prune compat pruneContainers // --- // tags: @@ -106,6 +110,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/prune"), s.APIHandler(handlers.PruneContainers)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/prune", s.APIHandler(handlers.PruneContainers)).Methods(http.MethodPost) // swagger:operation DELETE /containers/{name} compat removeContainer // --- // tags: @@ -145,6 +151,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}"), s.APIHandler(generic.RemoveContainer)).Methods(http.MethodDelete) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}", s.APIHandler(generic.RemoveContainer)).Methods(http.MethodDelete) // swagger:operation GET /containers/{name}/json compat getContainer // --- // tags: @@ -172,6 +180,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/json"), s.APIHandler(generic.GetContainer)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/json", s.APIHandler(generic.GetContainer)).Methods(http.MethodGet) // swagger:operation POST /containers/{name}/kill compat killContainer // --- // tags: @@ -202,6 +212,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/kill"), s.APIHandler(generic.KillContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/kill", s.APIHandler(generic.KillContainer)).Methods(http.MethodPost) // swagger:operation GET /containers/{name}/logs compat logsFromContainer // --- // tags: @@ -254,6 +266,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/logs"), s.APIHandler(generic.LogsFromContainer)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/logs", s.APIHandler(generic.LogsFromContainer)).Methods(http.MethodGet) // swagger:operation POST /containers/{name}/pause compat pauseContainer // --- // tags: @@ -276,7 +290,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/pause"), s.APIHandler(handlers.PauseContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/pause", s.APIHandler(handlers.PauseContainer)).Methods(http.MethodPost) r.HandleFunc(VersionedPath("/containers/{name}/rename"), s.APIHandler(handlers.UnsupportedHandler)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/rename", s.APIHandler(handlers.UnsupportedHandler)).Methods(http.MethodPost) // swagger:operation POST /containers/{name}/restart compat restartContainer // --- // tags: @@ -302,6 +320,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/restart"), s.APIHandler(handlers.RestartContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/restart", s.APIHandler(handlers.RestartContainer)).Methods(http.MethodPost) // swagger:operation POST /containers/{name}/start compat startContainer // --- // tags: @@ -330,6 +350,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/start"), s.APIHandler(handlers.StartContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/start", s.APIHandler(handlers.StartContainer)).Methods(http.MethodPost) // swagger:operation GET /containers/{name}/stats compat statsContainer // --- // tags: @@ -357,6 +379,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/stats"), s.APIHandler(generic.StatsContainer)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/stats", s.APIHandler(generic.StatsContainer)).Methods(http.MethodGet) // swagger:operation POST /containers/{name}/stop compat stopContainer // --- // tags: @@ -385,6 +409,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/stop"), s.APIHandler(handlers.StopContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/stop", s.APIHandler(handlers.StopContainer)).Methods(http.MethodPost) // swagger:operation GET /containers/{name}/top compat topContainer // --- // tags: @@ -410,6 +436,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/top"), s.APIHandler(handlers.TopContainer)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/top", s.APIHandler(handlers.TopContainer)).Methods(http.MethodGet) // swagger:operation POST /containers/{name}/unpause compat unpauseContainer // --- // tags: @@ -432,6 +460,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/unpause"), s.APIHandler(handlers.UnpauseContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/unpause", s.APIHandler(handlers.UnpauseContainer)).Methods(http.MethodPost) // swagger:operation POST /containers/{name}/wait compat waitContainer // --- // tags: @@ -465,6 +495,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/wait"), s.APIHandler(generic.WaitContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/wait", s.APIHandler(generic.WaitContainer)).Methods(http.MethodPost) // swagger:operation POST /containers/{name}/attach compat attachContainer // --- // tags: @@ -520,6 +552,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/attach"), s.APIHandler(handlers.AttachContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/attach", s.APIHandler(handlers.AttachContainer)).Methods(http.MethodPost) // swagger:operation POST /containers/{name}/resize compat resizeContainer // --- // tags: @@ -552,6 +586,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/containers/{name}/resize"), s.APIHandler(handlers.ResizeContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/containers/{name}/resize", s.APIHandler(handlers.ResizeContainer)).Methods(http.MethodPost) /* libpod endpoints diff --git a/pkg/api/server/register_distribution.go b/pkg/api/server/register_distribution.go index f03662224..730129d5d 100644 --- a/pkg/api/server/register_distribution.go +++ b/pkg/api/server/register_distribution.go @@ -7,5 +7,7 @@ import ( func (s *APIServer) registerDistributionHandlers(r *mux.Router) error { r.HandleFunc(VersionedPath("/distribution/{name}/json"), handlers.UnsupportedHandler) + // Added non version path to URI to support docker non versioned paths + r.HandleFunc("/distribution/{name}/json", handlers.UnsupportedHandler) return nil } diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go index bc3b62662..ea5d21882 100644 --- a/pkg/api/server/register_events.go +++ b/pkg/api/server/register_events.go @@ -35,5 +35,7 @@ func (s *APIServer) registerEventsHandlers(r *mux.Router) error { // 500: // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/events"), s.APIHandler(handlers.GetEvents)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/events", s.APIHandler(handlers.GetEvents)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_exec.go b/pkg/api/server/register_exec.go index ad62de3f5..76033a9ca 100644 --- a/pkg/api/server/register_exec.go +++ b/pkg/api/server/register_exec.go @@ -75,6 +75,8 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/containers/{name}/create"), s.APIHandler(handlers.CreateExec)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/containers/{name}/create", s.APIHandler(handlers.CreateExec)).Methods(http.MethodPost) // swagger:operation POST /exec/{id}/start compat startExec // --- // tags: @@ -111,6 +113,8 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/exec/{id}/start"), s.APIHandler(handlers.StartExec)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/exec/{id}/start", s.APIHandler(handlers.StartExec)).Methods(http.MethodPost) // swagger:operation POST /exec/{id}/resize compat resizeExec // --- // tags: @@ -142,6 +146,8 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/exec/{id}/resize"), s.APIHandler(handlers.ResizeExec)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/exec/{id}/resize", s.APIHandler(handlers.ResizeExec)).Methods(http.MethodPost) // swagger:operation GET /exec/{id}/json compat inspectExec // --- // tags: @@ -164,6 +170,8 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/exec/{id}/json"), s.APIHandler(handlers.InspectExec)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/exec/{id}/json", s.APIHandler(handlers.InspectExec)).Methods(http.MethodGet) /* libpod api follows diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index db04ecdc9..8c75c4d04 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -48,7 +48,11 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/images/create"), s.APIHandler(generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}") + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/create", s.APIHandler(generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}") r.Handle(VersionedPath("/images/create"), s.APIHandler(generic.CreateImageFromSrc)).Methods(http.MethodPost).Queries("fromSrc", "{fromSrc}") + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/create", s.APIHandler(generic.CreateImageFromSrc)).Methods(http.MethodPost).Queries("fromSrc", "{fromSrc}") // swagger:operation GET /images/json compat listImages // --- // tags: @@ -84,6 +88,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/json"), s.APIHandler(generic.GetImages)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/json", s.APIHandler(generic.GetImages)).Methods(http.MethodGet) // swagger:operation POST /images/load compat importImage // --- // tags: @@ -108,6 +114,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/load"), s.APIHandler(generic.LoadImages)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/load", s.APIHandler(generic.LoadImages)).Methods(http.MethodPost) // swagger:operation POST /images/prune compat pruneImages // --- // tags: @@ -133,6 +141,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/prune"), s.APIHandler(generic.PruneImages)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/prune", s.APIHandler(generic.PruneImages)).Methods(http.MethodPost) // swagger:operation GET /images/search compat searchImages // --- // tags: @@ -166,6 +176,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/search"), s.APIHandler(handlers.SearchImages)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/search", s.APIHandler(handlers.SearchImages)).Methods(http.MethodGet) // swagger:operation DELETE /images/{name:.*} compat removeImage // --- // tags: @@ -198,6 +210,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/{name:.*}"), s.APIHandler(handlers.RemoveImage)).Methods(http.MethodDelete) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/{name:.*}", s.APIHandler(handlers.RemoveImage)).Methods(http.MethodDelete) // swagger:operation GET /images/{name:.*}/get compat exportImage // --- // tags: @@ -221,6 +235,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/{name:.*}/get"), s.APIHandler(generic.ExportImage)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/{name:.*}/get", s.APIHandler(generic.ExportImage)).Methods(http.MethodGet) // swagger:operation GET /images/{name:.*}/history compat imageHistory // --- // tags: @@ -243,6 +259,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/images/{name:.*}/history"), s.APIHandler(handlers.HistoryImage)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/{name:.*}/history", s.APIHandler(handlers.HistoryImage)).Methods(http.MethodGet) // swagger:operation GET /images/{name:.*}/json compat inspectImage // --- // tags: @@ -265,6 +283,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/images/{name:.*}/json"), s.APIHandler(generic.GetImage)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/{name:.*}/json", s.APIHandler(generic.GetImage)).Methods(http.MethodGet) // swagger:operation POST /images/{name:.*}/tag compat tagImage // --- // tags: @@ -299,6 +319,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/{name:.*}/tag"), s.APIHandler(handlers.TagImage)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/images/{name:.*}/tag", s.APIHandler(handlers.TagImage)).Methods(http.MethodPost) // swagger:operation POST /commit compat commitContainer // --- // tags: @@ -344,6 +366,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/commit"), s.APIHandler(generic.CommitContainer)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/commit", s.APIHandler(generic.CommitContainer)).Methods(http.MethodPost) // swagger:operation POST /build compat buildImage // --- @@ -554,6 +578,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/build"), s.APIHandler(handlers.BuildImage)).Methods(http.MethodPost) + // Added non version path to URI to support docker non versioned paths + r.Handle("/build", s.APIHandler(handlers.BuildImage)).Methods(http.MethodPost) /* libpod endpoints */ @@ -942,6 +968,50 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/libpod/images/{name:.*}/tag"), s.APIHandler(handlers.TagImage)).Methods(http.MethodPost) - + // swagger:operation POST /commit libpod libpodCommitContainer + // --- + // tags: + // - containers + // summary: Commit + // description: Create a new image from a container + // parameters: + // - in: query + // name: container + // type: string + // description: the name or ID of a container + // - in: query + // name: repo + // type: string + // description: the repository name for the created image + // - in: query + // name: tag + // type: string + // description: tag name for the created image + // - in: query + // name: comment + // type: string + // description: commit message + // - in: query + // name: author + // type: string + // description: author of the image + // - in: query + // name: pause + // type: boolean + // description: pause the container before committing it + // - in: query + // name: changes + // type: string + // description: instructions to apply while committing in Dockerfile format + // produces: + // - application/json + // responses: + // 201: + // description: no error + // 404: + // $ref: '#/responses/NoSuchImage' + // 500: + // $ref: '#/responses/InternalError' + r.Handle(VersionedPath("/commit"), s.APIHandler(generic.CommitContainer)).Methods(http.MethodPost) return nil } diff --git a/pkg/api/server/register_info.go b/pkg/api/server/register_info.go index 36c467cc3..975a19fef 100644 --- a/pkg/api/server/register_info.go +++ b/pkg/api/server/register_info.go @@ -22,5 +22,7 @@ func (s *APIServer) registerInfoHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.Handle(VersionedPath("/info"), s.APIHandler(generic.GetInfo)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/info", s.APIHandler(generic.GetInfo)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_monitor.go b/pkg/api/server/register_monitor.go index dbe0d27ce..b821efbaa 100644 --- a/pkg/api/server/register_monitor.go +++ b/pkg/api/server/register_monitor.go @@ -7,5 +7,7 @@ import ( func (s *APIServer) registerMonitorHandlers(r *mux.Router) error { r.Handle(VersionedPath("/monitor"), s.APIHandler(handlers.UnsupportedHandler)) + // Added non version path to URI to support docker non versioned paths + r.Handle("/monitor", s.APIHandler(handlers.UnsupportedHandler)) return nil } diff --git a/pkg/api/server/register_plugins.go b/pkg/api/server/register_plugins.go index 479a79d1f..50026f6ad 100644 --- a/pkg/api/server/register_plugins.go +++ b/pkg/api/server/register_plugins.go @@ -7,5 +7,7 @@ import ( func (s *APIServer) registerPluginsHandlers(r *mux.Router) error { r.Handle(VersionedPath("/plugins"), s.APIHandler(handlers.UnsupportedHandler)) + // Added non version path to URI to support docker non versioned paths + r.Handle("/plugins", s.APIHandler(handlers.UnsupportedHandler)) return nil } diff --git a/pkg/api/server/register_swarm.go b/pkg/api/server/register_swarm.go index e37ac4e41..8a5588268 100644 --- a/pkg/api/server/register_swarm.go +++ b/pkg/api/server/register_swarm.go @@ -16,6 +16,14 @@ func (s *APIServer) registerSwarmHandlers(r *mux.Router) error { r.PathPrefix("/v{version:[0-9.]+}/services/").HandlerFunc(noSwarm) r.PathPrefix("/v{version:[0-9.]+}/swarm/").HandlerFunc(noSwarm) r.PathPrefix("/v{version:[0-9.]+}/tasks/").HandlerFunc(noSwarm) + + // Added non version path to URI to support docker non versioned paths + r.PathPrefix("/configs/").HandlerFunc(noSwarm) + r.PathPrefix("/nodes/").HandlerFunc(noSwarm) + r.PathPrefix("/secrets/").HandlerFunc(noSwarm) + r.PathPrefix("/services/").HandlerFunc(noSwarm) + r.PathPrefix("/swarm/").HandlerFunc(noSwarm) + r.PathPrefix("/tasks/").HandlerFunc(noSwarm) return nil } diff --git a/pkg/api/server/register_system.go b/pkg/api/server/register_system.go index 188c1cdac..4776692f5 100644 --- a/pkg/api/server/register_system.go +++ b/pkg/api/server/register_system.go @@ -9,5 +9,7 @@ import ( func (s *APIServer) registerSystemHandlers(r *mux.Router) error { r.Handle(VersionedPath("/system/df"), s.APIHandler(generic.GetDiskUsage)).Methods(http.MethodGet) + // Added non version path to URI to support docker non versioned paths + r.Handle("/system/df", s.APIHandler(generic.GetDiskUsage)).Methods(http.MethodGet) return nil } diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go index d1317904b..2cf249cc3 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -25,7 +25,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/create"), s.APIHandler(libpod.CreateVolume)).Methods(http.MethodPost) - // swagger:operation POST /libpod/volumes/json volumes listVolumes + // swagger:operation GET /libpod/volumes/json volumes listVolumes // --- // summary: List volumes // description: Returns a list of networks diff --git a/pkg/api/tags.yaml b/pkg/api/tags.yaml index 3bf2bb64f..571f49e44 100644 --- a/pkg/api/tags.yaml +++ b/pkg/api/tags.yaml @@ -18,4 +18,4 @@ tags: - name: images (compat) description: Actions related to images for the compatibility endpoints - name: system (compat) - description: Actions related to Podman and compatiblity engines + description: Actions related to Podman and compatibility engines diff --git a/pkg/apparmor/apparmor.go b/pkg/apparmor/apparmor.go index 45c029c07..1e824550d 100644 --- a/pkg/apparmor/apparmor.go +++ b/pkg/apparmor/apparmor.go @@ -2,6 +2,7 @@ package apparmor import ( "errors" + libpodVersion "github.com/containers/libpod/version" ) diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go index 43a3ef02d..495f9db49 100644 --- a/pkg/bindings/containers/create.go +++ b/pkg/bindings/containers/create.go @@ -11,7 +11,7 @@ import ( jsoniter "github.com/json-iterator/go" ) -func CreateWithSpec(ctx context.Context, s specgen.SpecGenerator) (utils.ContainerCreateResponse, error) { +func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator) (utils.ContainerCreateResponse, error) { var ccr utils.ContainerCreateResponse conn, err := bindings.GetClient(ctx) if err != nil { diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go index dc607c1b3..3f94fad01 100644 --- a/pkg/bindings/containers/healthcheck.go +++ b/pkg/bindings/containers/healthcheck.go @@ -2,10 +2,10 @@ package containers import ( "context" - "github.com/containers/libpod/pkg/bindings" "net/http" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/bindings" ) // RunHealthCheck executes the container's healthcheck and returns the health status of the diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go index 1fc774074..a4d065a14 100644 --- a/pkg/bindings/test/common_test.go +++ b/pkg/bindings/test/common_test.go @@ -1,6 +1,7 @@ package test_bindings import ( + "context" "fmt" "io/ioutil" "os" @@ -8,6 +9,9 @@ import ( "path/filepath" "strings" + . "github.com/containers/libpod/pkg/bindings" + "github.com/containers/libpod/pkg/bindings/containers" + "github.com/containers/libpod/pkg/specgen" "github.com/onsi/ginkgo" "github.com/onsi/gomega/gexec" "github.com/pkg/errors" @@ -55,6 +59,16 @@ type bindingTest struct { tempDirPath string runRoot string crioRoot string + conn context.Context +} + +func (b *bindingTest) NewConnection() error { + connText, err := NewConnection(context.Background(), b.sock) + if err != nil { + return err + } + b.conn = connText + return nil } func (b *bindingTest) runPodman(command []string) *gexec.Session { @@ -173,17 +187,27 @@ func (b *bindingTest) restoreImageFromCache(i testImage) { // Run a container within or without a pod // and add or append the alpine image to it -func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, podName *string) { - cmd := []string{"run", "-dt"} +func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, podName *string) (string, error) { + s := specgen.NewSpecGenerator(alpine.name) + s.Terminal = false + s.Command = []string{"top"} + if containerName != nil { + s.Name = *containerName + } if insidePod != nil && podName != nil { - pName := *podName - cmd = append(cmd, "--pod", pName) - } else if containerName != nil { - cName := *containerName - cmd = append(cmd, "--name", cName) - } - cmd = append(cmd, alpine.name, "top") - b.runPodman(cmd).Wait(45) + s.Pod = *podName + } + ctr, err := containers.CreateWithSpec(b.conn, s) + if err != nil { + return "", nil + } + err = containers.Start(b.conn, ctr.ID, nil) + if err != nil { + return "", err + } + waiting := "running" + _, err = containers.Wait(b.conn, ctr.ID, &waiting) + return ctr.ID, err } // This method creates a pod with the given pod name. diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index 299a78ac2..e7ef620d4 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -1,7 +1,6 @@ package test_bindings import ( - "context" "net/http" "strconv" "time" @@ -18,7 +17,6 @@ var _ = Describe("Podman containers ", func() { var ( bt *bindingTest s *gexec.Session - connText context.Context err error falseFlag bool = false trueFlag bool = true @@ -29,18 +27,18 @@ var _ = Describe("Podman containers ", func() { bt.RestoreImagesFromCache() s = bt.startAPIService() time.Sleep(1 * time.Second) - connText, err = bindings.NewConnection(context.Background(), bt.sock) + err := bt.NewConnection() Expect(err).To(BeNil()) }) AfterEach(func() { s.Kill() - bt.cleanup() + //bt.cleanup() }) It("podman pause a bogus container", func() { // Pausing bogus container should return 404 - err = containers.Pause(connText, "foobar") + err = containers.Pause(bt.conn, "foobar") Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) @@ -48,7 +46,7 @@ var _ = Describe("Podman containers ", func() { It("podman unpause a bogus container", func() { // Unpausing bogus container should return 404 - err = containers.Unpause(connText, "foobar") + err = containers.Unpause(bt.conn, "foobar") Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) @@ -57,12 +55,13 @@ var _ = Describe("Podman containers ", func() { It("podman pause a running container by name", func() { // Pausing by name should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - err := containers.Pause(connText, name) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) + Expect(err).To(BeNil()) + err = containers.Pause(bt.conn, name) Expect(err).To(BeNil()) // Ensure container is paused - data, err := containers.Inspect(connText, name, nil) + data, err := containers.Inspect(bt.conn, name, nil) Expect(err).To(BeNil()) Expect(data.State.Status).To(Equal("paused")) }) @@ -70,54 +69,60 @@ var _ = Describe("Podman containers ", func() { It("podman pause a running container by id", func() { // Pausing by id should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Pause(bt.conn, cid) Expect(err).To(BeNil()) // Ensure container is paused - data, err = containers.Inspect(connText, data.ID, nil) + data, err := containers.Inspect(bt.conn, cid, nil) + Expect(err).To(BeNil()) Expect(data.State.Status).To(Equal("paused")) }) It("podman unpause a running container by name", func() { // Unpausing by name should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - err := containers.Pause(connText, name) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Unpause(connText, name) + err = containers.Pause(bt.conn, name) + Expect(err).To(BeNil()) + err = containers.Unpause(bt.conn, name) Expect(err).To(BeNil()) // Ensure container is unpaused - data, err := containers.Inspect(connText, name, nil) + data, err := containers.Inspect(bt.conn, name, nil) + Expect(err).To(BeNil()) Expect(data.State.Status).To(Equal("running")) }) It("podman unpause a running container by ID", func() { // Unpausing by ID should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - // Pause by name - err := containers.Pause(connText, name) - data, err := containers.Inspect(connText, name, nil) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Unpause(connText, data.ID) + // Pause by name + err = containers.Pause(bt.conn, name) + //paused := "paused" + //_, err = containers.Wait(bt.conn, cid, &paused) + //Expect(err).To(BeNil()) + err = containers.Unpause(bt.conn, name) Expect(err).To(BeNil()) // Ensure container is unpaused - data, err = containers.Inspect(connText, name, nil) + data, err := containers.Inspect(bt.conn, name, nil) + Expect(err).To(BeNil()) Expect(data.State.Status).To(Equal("running")) }) It("podman pause a paused container by name", func() { // Pausing a paused container by name should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - err := containers.Pause(connText, name) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, name) + err = containers.Pause(bt.conn, name) + Expect(err).To(BeNil()) + err = containers.Pause(bt.conn, name) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -126,12 +131,11 @@ var _ = Describe("Podman containers ", func() { It("podman pause a paused container by id", func() { // Pausing a paused container by id should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Pause(bt.conn, cid) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Pause(bt.conn, cid) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -140,10 +144,11 @@ var _ = Describe("Podman containers ", func() { It("podman pause a stopped container by name", func() { // Pausing a stopped container by name should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - err := containers.Stop(connText, name, nil) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) + Expect(err).To(BeNil()) + err = containers.Stop(bt.conn, name, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, name) + err = containers.Pause(bt.conn, name) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -152,11 +157,11 @@ var _ = Describe("Podman containers ", func() { It("podman pause a stopped container by id", func() { // Pausing a stopped container by id should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) - err = containers.Stop(connText, data.ID, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Stop(bt.conn, cid, nil) + Expect(err).To(BeNil()) + err = containers.Pause(bt.conn, cid) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -165,12 +170,11 @@ var _ = Describe("Podman containers ", func() { It("podman remove a paused container by id without force", func() { // Removing a paused container without force should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Pause(bt.conn, cid) Expect(err).To(BeNil()) - err = containers.Remove(connText, data.ID, &falseFlag, &falseFlag) + err = containers.Remove(bt.conn, cid, &falseFlag, &falseFlag) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -187,22 +191,22 @@ var _ = Describe("Podman containers ", func() { // Removing a paused container with force should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Pause(bt.conn, cid) Expect(err).To(BeNil()) - err = containers.Remove(connText, data.ID, &trueFlag, &falseFlag) + err = containers.Remove(bt.conn, cid, &trueFlag, &falseFlag) Expect(err).To(BeNil()) }) It("podman stop a paused container by name", func() { // Stopping a paused container by name should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - err := containers.Pause(connText, name) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) + Expect(err).To(BeNil()) + err = containers.Pause(bt.conn, name) Expect(err).To(BeNil()) - err = containers.Stop(connText, name, nil) + err = containers.Stop(bt.conn, name, nil) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -211,12 +215,11 @@ var _ = Describe("Podman containers ", func() { It("podman stop a paused container by id", func() { // Stopping a paused container by id should fail var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Pause(connText, data.ID) + err = containers.Pause(bt.conn, cid) Expect(err).To(BeNil()) - err = containers.Stop(connText, data.ID, nil) + err = containers.Stop(bt.conn, cid, nil) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -225,12 +228,13 @@ var _ = Describe("Podman containers ", func() { It("podman stop a running container by name", func() { // Stopping a running container by name should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - err := containers.Stop(connText, name, nil) + _, err := bt.RunTopContainer(&name, &falseFlag, nil) + Expect(err).To(BeNil()) + err = containers.Stop(bt.conn, name, nil) Expect(err).To(BeNil()) // Ensure container is stopped - data, err := containers.Inspect(connText, name, nil) + data, err := containers.Inspect(bt.conn, name, nil) Expect(err).To(BeNil()) Expect(isStopped(data.State.Status)).To(BeTrue()) }) @@ -238,14 +242,13 @@ var _ = Describe("Podman containers ", func() { It("podman stop a running container by ID", func() { // Stopping a running container by ID should work var name = "top" - bt.RunTopContainer(&name, &falseFlag, nil) - data, err := containers.Inspect(connText, name, nil) + cid, err := bt.RunTopContainer(&name, &falseFlag, nil) Expect(err).To(BeNil()) - err = containers.Stop(connText, data.ID, nil) + err = containers.Stop(bt.conn, cid, nil) Expect(err).To(BeNil()) // Ensure container is stopped - data, err = containers.Inspect(connText, name, nil) + data, err := containers.Inspect(bt.conn, name, nil) Expect(err).To(BeNil()) Expect(isStopped(data.State.Status)).To(BeTrue()) }) @@ -255,19 +258,20 @@ var _ = Describe("Podman containers ", func() { name = "top" exitCode int32 = -1 ) - _, err := containers.Wait(connText, "foobar", nil) + _, err := containers.Wait(bt.conn, "foobar", nil) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) errChan := make(chan error) - bt.RunTopContainer(&name, nil, nil) + _, err = bt.RunTopContainer(&name, nil, nil) + Expect(err).To(BeNil()) go func() { - exitCode, err = containers.Wait(connText, name, nil) + exitCode, err = containers.Wait(bt.conn, name, nil) errChan <- err close(errChan) }() - err = containers.Stop(connText, name, nil) + err = containers.Stop(bt.conn, name, nil) Expect(err).To(BeNil()) wait := <-errChan Expect(wait).To(BeNil()) @@ -282,13 +286,14 @@ var _ = Describe("Podman containers ", func() { unpause = "running" ) errChan := make(chan error) - bt.RunTopContainer(&name, nil, nil) + _, err := bt.RunTopContainer(&name, nil, nil) + Expect(err).To(BeNil()) go func() { - exitCode, err = containers.Wait(connText, name, &pause) + exitCode, err = containers.Wait(bt.conn, name, &pause) errChan <- err close(errChan) }() - err := containers.Pause(connText, name) + err = containers.Pause(bt.conn, name) Expect(err).To(BeNil()) wait := <-errChan Expect(wait).To(BeNil()) @@ -296,11 +301,11 @@ var _ = Describe("Podman containers ", func() { errChan = make(chan error) go func() { - exitCode, err = containers.Wait(connText, name, &unpause) + exitCode, err = containers.Wait(bt.conn, name, &unpause) errChan <- err close(errChan) }() - err = containers.Unpause(connText, name) + err = containers.Unpause(bt.conn, name) Expect(err).To(BeNil()) unPausewait := <-errChan Expect(unPausewait).To(BeNil()) diff --git a/pkg/bindings/test/create_test.go b/pkg/bindings/test/create_test.go new file mode 100644 index 000000000..f83a9b14d --- /dev/null +++ b/pkg/bindings/test/create_test.go @@ -0,0 +1,50 @@ +package test_bindings + +import ( + "time" + + "github.com/containers/libpod/pkg/bindings/containers" + "github.com/containers/libpod/pkg/specgen" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Create containers ", func() { + var ( + bt *bindingTest + s *gexec.Session + ) + + BeforeEach(func() { + bt = newBindingTest() + bt.RestoreImagesFromCache() + s = bt.startAPIService() + time.Sleep(1 * time.Second) + err := bt.NewConnection() + Expect(err).To(BeNil()) + }) + + AfterEach(func() { + s.Kill() + bt.cleanup() + }) + + It("create a container running top", func() { + s := specgen.NewSpecGenerator(alpine.name) + s.Command = []string{"top"} + s.Terminal = true + s.Name = "top" + ctr, err := containers.CreateWithSpec(bt.conn, s) + Expect(err).To(BeNil()) + data, err := containers.Inspect(bt.conn, ctr.ID, nil) + Expect(err).To(BeNil()) + Expect(data.Name).To(Equal("top")) + err = containers.Start(bt.conn, ctr.ID, nil) + Expect(err).To(BeNil()) + data, err = containers.Inspect(bt.conn, ctr.ID, nil) + Expect(err).To(BeNil()) + Expect(data.State.Status).To(Equal("running")) + }) + +}) diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index 8eef28502..17b3b254a 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -1,7 +1,6 @@ package test_bindings import ( - "context" "net/http" "os" "path/filepath" @@ -22,7 +21,6 @@ var _ = Describe("Podman images", func() { //podmanTest *PodmanTestIntegration bt *bindingTest s *gexec.Session - connText context.Context err error falseFlag bool = false trueFlag bool = true @@ -40,7 +38,7 @@ var _ = Describe("Podman images", func() { bt.RestoreImagesFromCache() s = bt.startAPIService() time.Sleep(1 * time.Second) - connText, err = bindings.NewConnection(context.Background(), bt.sock) + err := bt.NewConnection() Expect(err).To(BeNil()) }) @@ -53,32 +51,32 @@ var _ = Describe("Podman images", func() { }) It("inspect image", func() { // Inspect invalid image be 404 - _, err = images.GetImage(connText, "foobar5000", nil) + _, err = images.GetImage(bt.conn, "foobar5000", nil) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Inspect by short name - data, err := images.GetImage(connText, alpine.shortName, nil) + data, err := images.GetImage(bt.conn, alpine.shortName, nil) Expect(err).To(BeNil()) // Inspect with full ID - _, err = images.GetImage(connText, data.ID, nil) + _, err = images.GetImage(bt.conn, data.ID, nil) Expect(err).To(BeNil()) // Inspect with partial ID - _, err = images.GetImage(connText, data.ID[0:12], nil) + _, err = images.GetImage(bt.conn, data.ID[0:12], nil) Expect(err).To(BeNil()) // Inspect by long name - _, err = images.GetImage(connText, alpine.name, nil) + _, err = images.GetImage(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) // TODO it looks like the images API alwaays returns size regardless // of bool or not. What should we do ? //Expect(data.Size).To(BeZero()) // Enabling the size parameter should result in size being populated - data, err = images.GetImage(connText, alpine.name, &trueFlag) + data, err = images.GetImage(bt.conn, alpine.name, &trueFlag) Expect(err).To(BeNil()) Expect(data.Size).To(BeNumerically(">", 0)) }) @@ -86,49 +84,50 @@ var _ = Describe("Podman images", func() { // Test to validate the remove image api It("remove image", func() { // Remove invalid image should be a 404 - _, err = images.Remove(connText, "foobar5000", &falseFlag) + _, err = images.Remove(bt.conn, "foobar5000", &falseFlag) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Remove an image by name, validate image is removed and error is nil - inspectData, err := images.GetImage(connText, busybox.shortName, nil) + inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) Expect(err).To(BeNil()) - response, err := images.Remove(connText, busybox.shortName, nil) + response, err := images.Remove(bt.conn, busybox.shortName, nil) Expect(err).To(BeNil()) Expect(inspectData.ID).To(Equal(response[0]["Deleted"])) - inspectData, err = images.GetImage(connText, busybox.shortName, nil) + inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Start a container with alpine image var top string = "top" - bt.RunTopContainer(&top, &falseFlag, nil) + _, err = bt.RunTopContainer(&top, &falseFlag, nil) + Expect(err).To(BeNil()) // we should now have a container called "top" running - containerResponse, err := containers.Inspect(connText, "top", &falseFlag) + containerResponse, err := containers.Inspect(bt.conn, "top", &falseFlag) Expect(err).To(BeNil()) Expect(containerResponse.Name).To(Equal("top")) // try to remove the image "alpine". This should fail since we are not force // deleting hence image cannot be deleted until the container is deleted. - response, err = images.Remove(connText, alpine.shortName, &falseFlag) + response, err = images.Remove(bt.conn, alpine.shortName, &falseFlag) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) // Removing the image "alpine" where force = true - response, err = images.Remove(connText, alpine.shortName, &trueFlag) + response, err = images.Remove(bt.conn, alpine.shortName, &trueFlag) Expect(err).To(BeNil()) // Checking if both the images are gone as well as the container is deleted - inspectData, err = images.GetImage(connText, busybox.shortName, nil) + inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) - inspectData, err = images.GetImage(connText, alpine.shortName, nil) + inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) - _, err = containers.Inspect(connText, "top", &falseFlag) + _, err = containers.Inspect(bt.conn, "top", &falseFlag) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) }) @@ -136,17 +135,17 @@ var _ = Describe("Podman images", func() { // Tests to validate the image tag command. It("tag image", func() { // Validates if invalid image name is given a bad response is encountered. - err = images.Tag(connText, "dummy", "demo", alpine.shortName) + err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) - // Validates if the image is tagged sucessfully. - err = images.Tag(connText, alpine.shortName, "demo", alpine.shortName) + // Validates if the image is tagged successfully. + err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName) Expect(err).To(BeNil()) //Validates if name updates when the image is retagged. - _, err := images.GetImage(connText, "alpine:demo", nil) + _, err := images.GetImage(bt.conn, "alpine:demo", nil) Expect(err).To(BeNil()) }) @@ -154,7 +153,7 @@ var _ = Describe("Podman images", func() { // Test to validate the List images command. It("List image", func() { // Array to hold the list of images returned - imageSummary, err := images.List(connText, nil, nil) + imageSummary, err := images.List(bt.conn, nil, nil) // There Should be no errors in the response. Expect(err).To(BeNil()) // Since in the begin context two images are created the @@ -164,7 +163,7 @@ var _ = Describe("Podman images", func() { // Adding one more image. There Should be no errors in the response. // And the count should be three now. bt.Pull("busybox:glibc") - imageSummary, err = images.List(connText, nil, nil) + imageSummary, err = images.List(bt.conn, nil, nil) Expect(err).To(BeNil()) Expect(len(imageSummary)).To(Equal(3)) @@ -179,13 +178,13 @@ var _ = Describe("Podman images", func() { // List images with a filter filters := make(map[string][]string) filters["reference"] = []string{alpine.name} - filteredImages, err := images.List(connText, &falseFlag, filters) + filteredImages, err := images.List(bt.conn, &falseFlag, filters) Expect(err).To(BeNil()) Expect(len(filteredImages)).To(BeNumerically("==", 1)) // List images with a bad filter filters["name"] = []string{alpine.name} - _, err = images.List(connText, &falseFlag, filters) + _, err = images.List(bt.conn, &falseFlag, filters) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -193,64 +192,64 @@ var _ = Describe("Podman images", func() { It("Image Exists", func() { // exists on bogus image should be false, with no error - exists, err := images.Exists(connText, "foobar") + exists, err := images.Exists(bt.conn, "foobar") Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) // exists with shortname should be true - exists, err = images.Exists(connText, alpine.shortName) + exists, err = images.Exists(bt.conn, alpine.shortName) Expect(err).To(BeNil()) Expect(exists).To(BeTrue()) // exists with fqname should be true - exists, err = images.Exists(connText, alpine.name) + exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeTrue()) }) It("Load|Import Image", func() { // load an image - _, err := images.Remove(connText, alpine.name, nil) + _, err := images.Remove(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) - exists, err := images.Exists(connText, alpine.name) + exists, err := images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) defer f.Close() Expect(err).To(BeNil()) - names, err := images.Load(connText, f, nil) + names, err := images.Load(bt.conn, f, nil) Expect(err).To(BeNil()) Expect(names).To(Equal(alpine.name)) - exists, err = images.Exists(connText, alpine.name) + exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeTrue()) // load with a repo name f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) Expect(err).To(BeNil()) - _, err = images.Remove(connText, alpine.name, nil) + _, err = images.Remove(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) - exists, err = images.Exists(connText, alpine.name) + exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) newName := "quay.io/newname:fizzle" - names, err = images.Load(connText, f, &newName) + names, err = images.Load(bt.conn, f, &newName) Expect(err).To(BeNil()) Expect(names).To(Equal(alpine.name)) - exists, err = images.Exists(connText, newName) + exists, err = images.Exists(bt.conn, newName) Expect(err).To(BeNil()) Expect(exists).To(BeTrue()) // load with a bad repo name should trigger a 500 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) Expect(err).To(BeNil()) - _, err = images.Remove(connText, alpine.name, nil) + _, err = images.Remove(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) - exists, err = images.Exists(connText, alpine.name) + exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) badName := "quay.io/newName:fizzle" - _, err = images.Load(connText, f, &badName) + _, err = images.Load(bt.conn, f, &badName) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -262,7 +261,7 @@ var _ = Describe("Podman images", func() { w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) defer w.Close() Expect(err).To(BeNil()) - err = images.Export(connText, alpine.name, w, nil, nil) + err = images.Export(bt.conn, alpine.name, w, nil, nil) Expect(err).To(BeNil()) _, err = os.Stat(exportPath) Expect(err).To(BeNil()) @@ -272,9 +271,9 @@ var _ = Describe("Podman images", func() { It("Import Image", func() { // load an image - _, err = images.Remove(connText, alpine.name, nil) + _, err = images.Remove(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) - exists, err := images.Exists(connText, alpine.name) + exists, err := images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) @@ -282,27 +281,27 @@ var _ = Describe("Podman images", func() { Expect(err).To(BeNil()) changes := []string{"CMD /bin/foobar"} testMessage := "test_import" - _, err = images.Import(connText, changes, &testMessage, &alpine.name, nil, f) + _, err = images.Import(bt.conn, changes, &testMessage, &alpine.name, nil, f) Expect(err).To(BeNil()) - exists, err = images.Exists(connText, alpine.name) + exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeTrue()) - data, err := images.GetImage(connText, alpine.name, nil) + data, err := images.GetImage(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) Expect(data.Comment).To(Equal(testMessage)) }) It("History Image", func() { // a bogus name should return a 404 - _, err := images.History(connText, "foobar") + _, err := images.History(bt.conn, "foobar") Expect(err).To(Not(BeNil())) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) var foundID bool - data, err := images.GetImage(connText, alpine.name, nil) + data, err := images.GetImage(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) - history, err := images.History(connText, alpine.name) + history, err := images.History(bt.conn, alpine.name) Expect(err).To(BeNil()) for _, i := range history { if i.ID == data.ID { @@ -314,7 +313,7 @@ var _ = Describe("Podman images", func() { }) It("Search for an image", func() { - imgs, err := images.Search(connText, "alpine", nil, nil) + imgs, err := images.Search(bt.conn, "alpine", nil, nil) Expect(err).To(BeNil()) Expect(len(imgs)).To(BeNumerically(">", 1)) var foundAlpine bool @@ -328,21 +327,21 @@ var _ = Describe("Podman images", func() { // Search for alpine with a limit of 10 ten := 10 - imgs, err = images.Search(connText, "docker.io/alpine", &ten, nil) + imgs, err = images.Search(bt.conn, "docker.io/alpine", &ten, nil) Expect(err).To(BeNil()) Expect(len(imgs)).To(BeNumerically("<=", 10)) // Search for alpine with stars greater than 100 filters := make(map[string][]string) filters["stars"] = []string{"100"} - imgs, err = images.Search(connText, "docker.io/alpine", nil, filters) + imgs, err = images.Search(bt.conn, "docker.io/alpine", nil, filters) Expect(err).To(BeNil()) for _, i := range imgs { Expect(i.Stars).To(BeNumerically(">=", 100)) } // Search with a fqdn - imgs, err = images.Search(connText, "quay.io/libpod/alpine_nginx", nil, nil) + imgs, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", nil, nil) Expect(len(imgs)).To(BeNumerically(">=", 1)) }) diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go index afffee4e6..7e29265b7 100644 --- a/pkg/bindings/test/pods_test.go +++ b/pkg/bindings/test/pods_test.go @@ -1,7 +1,6 @@ package test_bindings import ( - "context" "net/http" "time" @@ -17,7 +16,6 @@ var _ = Describe("Podman pods", func() { var ( bt *bindingTest s *gexec.Session - connText context.Context newpod string err error trueFlag bool = true @@ -30,7 +28,7 @@ var _ = Describe("Podman pods", func() { bt.Podcreate(&newpod) s = bt.startAPIService() time.Sleep(1 * time.Second) - connText, err = bindings.NewConnection(context.Background(), bt.sock) + err := bt.NewConnection() Expect(err).To(BeNil()) }) @@ -41,13 +39,13 @@ var _ = Describe("Podman pods", func() { It("inspect pod", func() { //Inspect an invalid pod name - _, err := pods.Inspect(connText, "dummyname") + _, err := pods.Inspect(bt.conn, "dummyname") Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) //Inspect an valid pod name - response, err := pods.Inspect(connText, newpod) + response, err := pods.Inspect(bt.conn, newpod) Expect(err).To(BeNil()) Expect(response.Config.Name).To(Equal(newpod)) }) @@ -55,12 +53,13 @@ var _ = Describe("Podman pods", func() { // Test validates the list all api returns It("list pod", func() { //List all the pods in the current instance - podSummary, err := pods.List(connText, nil) + podSummary, err := pods.List(bt.conn, nil) Expect(err).To(BeNil()) Expect(len(podSummary)).To(Equal(1)) // Adding an alpine container to the existing pod - bt.RunTopContainer(nil, &trueFlag, &newpod) - podSummary, err = pods.List(connText, nil) + _, err = bt.RunTopContainer(nil, &trueFlag, &newpod) + Expect(err).To(BeNil()) + podSummary, err = pods.List(bt.conn, nil) // Verify no errors. Expect(err).To(BeNil()) // Verify number of containers in the pod. @@ -69,7 +68,7 @@ var _ = Describe("Podman pods", func() { // Add multiple pods and verify them by name and size. var newpod2 string = "newpod2" bt.Podcreate(&newpod2) - podSummary, err = pods.List(connText, nil) + podSummary, err = pods.List(bt.conn, nil) Expect(len(podSummary)).To(Equal(2)) var names []string for _, i := range podSummary { @@ -83,19 +82,19 @@ var _ = Describe("Podman pods", func() { // Validate list pod with filters //filters := make(map[string][]string) //filters["name"] = []string{newpod} - //filteredPods, err := pods.List(connText, filters) + //filteredPods, err := pods.List(bt.conn, filters) //Expect(err).To(BeNil()) //Expect(len(filteredPods)).To(BeNumerically("==", 1)) }) // The test validates if the exists responds It("exists pod", func() { - response, err := pods.Exists(connText, "dummyName") + response, err := pods.Exists(bt.conn, "dummyName") Expect(err).To(BeNil()) Expect(response).To(BeFalse()) // Should exit with no error and response should be true - response, err = pods.Exists(connText, "newpod") + response, err = pods.Exists(bt.conn, "newpod") Expect(err).To(BeNil()) Expect(response).To(BeTrue()) }) @@ -103,23 +102,24 @@ var _ = Describe("Podman pods", func() { // This test validates if All running containers within // each specified pod are paused and unpaused It("pause upause pod", func() { + // TODO fix this + Skip("Pod behavior is jacked right now.") // Pause invalid container - err := pods.Pause(connText, "dummyName") + err := pods.Pause(bt.conn, "dummyName") Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Adding an alpine container to the existing pod - bt.RunTopContainer(nil, &trueFlag, &newpod) - response, err := pods.Inspect(connText, newpod) + _, err = bt.RunTopContainer(nil, &trueFlag, &newpod) Expect(err).To(BeNil()) // Binding needs to be modified to inspect the pod state. - // Since we dont have a pod state we inspect the states of the containers within the pod. + // Since we don't have a pod state we inspect the states of the containers within the pod. // Pause a valid container - err = pods.Pause(connText, newpod) + err = pods.Pause(bt.conn, newpod) Expect(err).To(BeNil()) - response, err = pods.Inspect(connText, newpod) + response, err := pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStatePaused)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). @@ -127,9 +127,9 @@ var _ = Describe("Podman pods", func() { } // Unpause a valid container - err = pods.Unpause(connText, newpod) + err = pods.Unpause(bt.conn, newpod) Expect(err).To(BeNil()) - response, err = pods.Inspect(connText, newpod) + response, err = pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStateRunning)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). @@ -139,28 +139,28 @@ var _ = Describe("Podman pods", func() { It("start stop restart pod", func() { // Start an invalid pod - err = pods.Start(connText, "dummyName") + err = pods.Start(bt.conn, "dummyName") Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Stop an invalid pod - err = pods.Stop(connText, "dummyName", nil) + err = pods.Stop(bt.conn, "dummyName", nil) Expect(err).ToNot(BeNil()) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Restart an invalid pod - err = pods.Restart(connText, "dummyName") + err = pods.Restart(bt.conn, "dummyName") Expect(err).ToNot(BeNil()) code, _ = bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Start a valid pod and inspect status of each container - err = pods.Start(connText, newpod) + err = pods.Start(bt.conn, newpod) Expect(err).To(BeNil()) - response, err := pods.Inspect(connText, newpod) + response, err := pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStateRunning)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). @@ -168,13 +168,13 @@ var _ = Describe("Podman pods", func() { } // Start an already running pod - err = pods.Start(connText, newpod) + err = pods.Start(bt.conn, newpod) Expect(err).To(BeNil()) // Stop the running pods - err = pods.Stop(connText, newpod, nil) + err = pods.Stop(bt.conn, newpod, nil) Expect(err).To(BeNil()) - response, _ = pods.Inspect(connText, newpod) + response, _ = pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStateExited)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). @@ -182,12 +182,12 @@ var _ = Describe("Podman pods", func() { } // Stop an already stopped pod - err = pods.Stop(connText, newpod, nil) + err = pods.Stop(bt.conn, newpod, nil) Expect(err).To(BeNil()) - err = pods.Restart(connText, newpod) + err = pods.Restart(bt.conn, newpod) Expect(err).To(BeNil()) - response, _ = pods.Inspect(connText, newpod) + response, _ = pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStateRunning)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). @@ -195,58 +195,58 @@ var _ = Describe("Podman pods", func() { } }) - // Test to validate all the pods in the stopped/exited state are pruned sucessfully. + // Test to validate all the pods in the stopped/exited state are pruned successfully. It("prune pod", func() { // Add a new pod var newpod2 string = "newpod2" bt.Podcreate(&newpod2) // No pods pruned since no pod in exited state - err = pods.Prune(connText) + err = pods.Prune(bt.conn) Expect(err).To(BeNil()) - podSummary, err := pods.List(connText, nil) + podSummary, err := pods.List(bt.conn, nil) Expect(err).To(BeNil()) Expect(len(podSummary)).To(Equal(2)) // Prune only one pod which is in exited state. // Start then stop a pod. // pod moves to exited state one pod should be pruned now. - err = pods.Start(connText, newpod) + err = pods.Start(bt.conn, newpod) Expect(err).To(BeNil()) - err = pods.Stop(connText, newpod, nil) + err = pods.Stop(bt.conn, newpod, nil) Expect(err).To(BeNil()) - response, err := pods.Inspect(connText, newpod) + response, err := pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStateExited)) - err = pods.Prune(connText) + err = pods.Prune(bt.conn) Expect(err).To(BeNil()) - podSummary, err = pods.List(connText, nil) + podSummary, err = pods.List(bt.conn, nil) Expect(err).To(BeNil()) Expect(len(podSummary)).To(Equal(1)) // Test prune all pods in exited state. bt.Podcreate(&newpod) - err = pods.Start(connText, newpod) + err = pods.Start(bt.conn, newpod) Expect(err).To(BeNil()) - err = pods.Start(connText, newpod2) + err = pods.Start(bt.conn, newpod2) Expect(err).To(BeNil()) - err = pods.Stop(connText, newpod, nil) + err = pods.Stop(bt.conn, newpod, nil) Expect(err).To(BeNil()) - response, err = pods.Inspect(connText, newpod) + response, err = pods.Inspect(bt.conn, newpod) Expect(response.State.Status).To(Equal(define.PodStateExited)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). To(Equal(define.ContainerStateStopped)) } - err = pods.Stop(connText, newpod2, nil) + err = pods.Stop(bt.conn, newpod2, nil) Expect(err).To(BeNil()) - response, err = pods.Inspect(connText, newpod2) + response, err = pods.Inspect(bt.conn, newpod2) Expect(response.State.Status).To(Equal(define.PodStateExited)) for _, i := range response.Containers { Expect(define.StringToContainerStatus(i.State)). To(Equal(define.ContainerStateStopped)) } - err = pods.Prune(connText) + err = pods.Prune(bt.conn) Expect(err).To(BeNil()) - podSummary, err = pods.List(connText, nil) + podSummary, err = pods.List(bt.conn, nil) Expect(err).To(BeNil()) Expect(len(podSummary)).To(Equal(0)) }) diff --git a/pkg/capabilities/capabilities.go b/pkg/capabilities/capabilities.go deleted file mode 100644 index ea22498b8..000000000 --- a/pkg/capabilities/capabilities.go +++ /dev/null @@ -1,129 +0,0 @@ -package capabilities - -// Copyright 2013-2018 Docker, Inc. - -// NOTE: this package has been copied from github.com/docker/docker but been -// changed significantly to fit the needs of libpod. - -import ( - "strings" - - "github.com/containers/libpod/pkg/util" - "github.com/pkg/errors" - "github.com/syndtr/gocapability/capability" -) - -var ( - // Used internally and populated during init(). - capabilityList []string - - // ErrUnknownCapability is thrown when an unknown capability is processed. - ErrUnknownCapability = errors.New("unknown capability") -) - -// All is a special value used to add/drop all known capababilities. -// Useful on the CLI for `--cap-add=all` etc. -const All = "ALL" - -func init() { - last := capability.CAP_LAST_CAP - // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap - if last == capability.Cap(63) { - last = capability.CAP_BLOCK_SUSPEND - } - for _, cap := range capability.List() { - if cap > last { - continue - } - capabilityList = append(capabilityList, "CAP_"+strings.ToUpper(cap.String())) - } -} - -// AllCapabilities returns all known capabilities. -func AllCapabilities() []string { - return capabilityList -} - -// normalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet -// present). -func normalizeCapabilities(caps []string) ([]string, error) { - normalized := make([]string, len(caps)) - for i, c := range caps { - c = strings.ToUpper(c) - if c == All { - normalized = append(normalized, c) - continue - } - if !strings.HasPrefix(c, "CAP_") { - c = "CAP_" + c - } - if !util.StringInSlice(c, capabilityList) { - return nil, errors.Wrapf(ErrUnknownCapability, "%q", c) - } - normalized[i] = c - } - return normalized, nil -} - -// ValidateCapabilities validates if caps only contains valid capabilities. -func ValidateCapabilities(caps []string) error { - for _, c := range caps { - if !util.StringInSlice(c, capabilityList) { - return errors.Wrapf(ErrUnknownCapability, "%q", c) - } - } - return nil -} - -// MergeCapabilities computes a set of capabilities by adding capapbitilities -// to or dropping them from base. -// -// Note that "ALL" will cause all known capabilities to be added/dropped but -// the ones specified to be dropped/added. -func MergeCapabilities(base, adds, drops []string) ([]string, error) { - if len(adds) == 0 && len(drops) == 0 { - // Nothing to tweak; we're done - return base, nil - } - - capDrop, err := normalizeCapabilities(drops) - if err != nil { - return nil, err - } - capAdd, err := normalizeCapabilities(adds) - if err != nil { - return nil, err - } - - // Make sure that capDrop and capAdd are distinct sets. - for _, drop := range capDrop { - if util.StringInSlice(drop, capAdd) { - return nil, errors.Errorf("capability %q cannot be dropped and added", drop) - } - } - - var caps []string - - switch { - case util.StringInSlice(All, capAdd): - // Add all capabilities except ones on capDrop - for _, c := range capabilityList { - if !util.StringInSlice(c, capDrop) { - caps = append(caps, c) - } - } - case util.StringInSlice(All, capDrop): - // "Drop" all capabilities; use what's in capAdd instead - caps = capAdd - default: - // First drop some capabilities - for _, c := range base { - if !util.StringInSlice(c, capDrop) { - caps = append(caps, c) - } - } - // Then add the list of capabilities from capAdd - caps = append(caps, capAdd...) - } - return caps, nil -} diff --git a/pkg/env/env.go b/pkg/env/env.go new file mode 100644 index 000000000..c6a1a0d28 --- /dev/null +++ b/pkg/env/env.go @@ -0,0 +1,126 @@ +// Package for processing environment variables. +package env + +// TODO: we need to add tests for this package. + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/pkg/errors" +) + +// DefaultEnvVariables sets $PATH and $TERM. +var DefaultEnvVariables = map[string]string{ + "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM": "xterm", +} + +const whiteSpaces = " \t" + +// ParseSlice parses the specified slice and transforms it into an environment +// map. +func ParseSlice(s []string) (map[string]string, error) { + env := make(map[string]string, len(s)) + for _, e := range s { + if err := parseEnv(env, e); err != nil { + return nil, err + } + } + return env, nil +} + +// Slice transforms the specified map of environment variables into a +// slice. If a value is non-empty, the key and value are joined with '='. +func Slice(m map[string]string) []string { + env := make([]string, len(m)) + for k, v := range m { + var s string + if len(v) > 0 { + s = fmt.Sprintf("%s=%s", k, v) + } else { + s = k + } + env = append(env, s) + } + return env +} + +// Join joins the two environment maps with override overriding base. +func Join(base map[string]string, override map[string]string) map[string]string { + if len(base) == 0 { + return override + } + for k, v := range override { + base[k] = v + } + return base +} + +// ParseFile parses the specified path for environment variables and returns them +// as a map. +func ParseFile(path string) (_ map[string]string, err error) { + env := make(map[string]string) + defer func() { + if err != nil { + err = errors.Wrapf(err, "error parsing env file %q", path) + } + }() + + fh, err := os.Open(path) + if err != nil { + return nil, err + } + defer fh.Close() + + scanner := bufio.NewScanner(fh) + for scanner.Scan() { + // trim the line from all leading whitespace first + line := strings.TrimLeft(scanner.Text(), whiteSpaces) + // line is not empty, and not starting with '#' + if len(line) > 0 && !strings.HasPrefix(line, "#") { + if err := parseEnv(env, line); err != nil { + return nil, err + } + } + } + return env, scanner.Err() +} + +func parseEnv(env map[string]string, line string) error { + data := strings.SplitN(line, "=", 2) + + // catch invalid variables such as "=" or "=A" + if data[0] == "" { + return errors.Errorf("invalid environment variable: %q", line) + } + + // trim the front of a variable, but nothing else + name := strings.TrimLeft(data[0], whiteSpaces) + if strings.ContainsAny(name, whiteSpaces) { + return errors.Errorf("name %q has white spaces, poorly formatted name", name) + } + + if len(data) > 1 { + env[name] = data[1] + } else { + if strings.HasSuffix(name, "*") { + name = strings.TrimSuffix(name, "*") + for _, e := range os.Environ() { + part := strings.SplitN(e, "=", 2) + if len(part) < 2 { + continue + } + if strings.HasPrefix(part[0], name) { + env[part[0]] = part[1] + } + } + } else if val, ok := os.LookupEnv(name); ok { + // if only a pass-through variable is given, clean it up. + env[name] = val + } + } + return nil +} diff --git a/pkg/hooks/exec/exec.go b/pkg/hooks/exec/exec.go index 4038e3d94..77b350573 100644 --- a/pkg/hooks/exec/exec.go +++ b/pkg/hooks/exec/exec.go @@ -5,13 +5,13 @@ import ( "bytes" "context" "fmt" - "github.com/sirupsen/logrus" "io" osexec "os/exec" "time" rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // DefaultPostKillTimeout is the recommended default post-kill timeout. diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go index 569f208d9..b04ce71a5 100644 --- a/pkg/inspect/inspect.go +++ b/pkg/inspect/inspect.go @@ -6,7 +6,7 @@ import ( "github.com/containers/image/v5/manifest" "github.com/containers/libpod/libpod/driver" "github.com/opencontainers/go-digest" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" ) // ImageData holds the inspect information of an image diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go index a249dd753..dff25f74f 100644 --- a/pkg/lookup/lookup.go +++ b/pkg/lookup/lookup.go @@ -4,7 +4,7 @@ import ( "os" "strconv" - "github.com/cyphar/filepath-securejoin" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/opencontainers/runc/libcontainer/user" "github.com/sirupsen/logrus" ) diff --git a/pkg/resolvconf/resolvconf.go b/pkg/resolvconf/resolvconf.go index e85bcb377..20618e2dc 100644 --- a/pkg/resolvconf/resolvconf.go +++ b/pkg/resolvconf/resolvconf.go @@ -10,7 +10,7 @@ import ( "sync" "github.com/containers/libpod/pkg/resolvconf/dns" - "github.com/docker/docker/pkg/ioutils" + "github.com/containers/storage/pkg/ioutils" "github.com/sirupsen/logrus" ) diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 02678a687..9b2255d61 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -112,6 +112,7 @@ type NetworkConfig struct { type SecurityConfig struct { CapAdd []string // cap-add CapDrop []string // cap-drop + CapRequired []string // cap-required LabelOpts []string //SecurityOpts NoNewPrivs bool //SecurityOpts ApparmorProfile string //SecurityOpts @@ -156,6 +157,7 @@ type CreateConfig struct { Resources CreateResourceConfig RestartPolicy string Rm bool //rm + Rmi bool //rmi StopSignal syscall.Signal // stop-signal StopTimeout uint // stop-timeout Systemd bool @@ -233,6 +235,10 @@ func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, err command = append(command, "--rm") } + if c.Rmi { + command = append(command, "--rmi") + } + return command, nil } diff --git a/pkg/spec/security.go b/pkg/spec/security.go index 3bad9f97a..0f8d36f00 100644 --- a/pkg/spec/security.go +++ b/pkg/spec/security.go @@ -4,11 +4,13 @@ import ( "fmt" "strings" + "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/pkg/capabilities" + "github.com/containers/libpod/pkg/util" "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // ToCreateOptions convert the SecurityConfig to a slice of container create @@ -113,28 +115,49 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon configSpec := g.Config var err error - var caplist []string + var defaultCaplist []string bounding := configSpec.Process.Capabilities.Bounding if useNotRoot(user.User) { - configSpec.Process.Capabilities.Bounding = caplist + configSpec.Process.Capabilities.Bounding = defaultCaplist } - caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop) + defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.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 + privCapRequired := []string{} + + if !c.Privileged && len(c.CapRequired) > 0 { + // Pass CapRequired in CapAdd field to normalize capabilities names + capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil) + if err != nil { + logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(c.CapRequired, ",")) + } else { + // Verify all capRequiered are in the defaultCapList + for _, cap := range capRequired { + if !util.StringInSlice(cap, defaultCaplist) { + privCapRequired = append(privCapRequired, cap) + } + } + } + if len(privCapRequired) == 0 { + defaultCaplist = capRequired + } else { + logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapRequired, ",")) + } + } + configSpec.Process.Capabilities.Bounding = defaultCaplist + configSpec.Process.Capabilities.Permitted = defaultCaplist + configSpec.Process.Capabilities.Inheritable = defaultCaplist + configSpec.Process.Capabilities.Effective = defaultCaplist + configSpec.Process.Capabilities.Ambient = defaultCaplist if useNotRoot(user.User) { - caplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop) + defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop) if err != nil { return err } } - configSpec.Process.Capabilities.Bounding = caplist + configSpec.Process.Capabilities.Bounding = defaultCaplist // HANDLE SECCOMP if c.SeccompProfilePath != "unconfined" { diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index a4ae22efd..8f0630b85 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -3,12 +3,15 @@ package createconfig import ( "strings" + "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" libpodconfig "github.com/containers/libpod/libpod/config" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/env" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/sysinfo" + "github.com/containers/libpod/pkg/util" "github.com/docker/go-units" "github.com/opencontainers/runc/libcontainer/user" spec "github.com/opencontainers/runtime-spec/specs-go" @@ -150,7 +153,6 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM for key, val := range config.Annotations { g.AddAnnotation(key, val) } - g.AddProcessEnv("container", "podman") addedResources := false @@ -292,6 +294,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } } + // Make sure to always set the default variables unless overridden in the + // config. + config.Env = env.Join(env.DefaultEnvVariables, config.Env) for name, val := range config.Env { g.AddProcessEnv(name, val) } @@ -327,6 +332,18 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } configSpec := g.Config + // If the container image specifies an label with a + // capabilities.ContainerImageLabel then split the comma separated list + // of capabilities and record them. This list indicates the only + // capabilities, required to run the container. + var capRequired []string + for key, val := range config.Labels { + if util.StringInSlice(key, capabilities.ContainerImageLabels) { + capRequired = strings.Split(val, ",") + } + } + config.Security.CapRequired = capRequired + if err := config.Security.ConfigureGenerator(&g, &config.User); err != nil { return nil, err } diff --git a/pkg/specgen/create.go b/pkg/specgen/create.go index 34f9ffac2..99a99083b 100644 --- a/pkg/specgen/create.go +++ b/pkg/specgen/create.go @@ -2,17 +2,17 @@ package specgen import ( "context" + "os" + "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/config" "github.com/containers/libpod/libpod/define" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "os" ) // MakeContainer creates a container based on the SpecGenerator func (s *SpecGenerator) MakeContainer(rt *libpod.Runtime) (*libpod.Container, error) { - var pod *libpod.Pod if err := s.validate(rt); err != nil { return nil, errors.Wrap(err, "invalid config provided") } @@ -21,7 +21,7 @@ func (s *SpecGenerator) MakeContainer(rt *libpod.Runtime) (*libpod.Container, er return nil, err } - options, err := s.createContainerOptions(rt, pod) + options, err := s.createContainerOptions(rt) if err != nil { return nil, err } @@ -45,7 +45,7 @@ func (s *SpecGenerator) MakeContainer(rt *libpod.Runtime) (*libpod.Container, er return rt.NewContainer(context.Background(), runtimeSpec, options...) } -func (s *SpecGenerator) createContainerOptions(rt *libpod.Runtime, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) { +func (s *SpecGenerator) createContainerOptions(rt *libpod.Runtime) ([]libpod.CtrCreateOption, error) { var options []libpod.CtrCreateOption var err error @@ -60,6 +60,10 @@ func (s *SpecGenerator) createContainerOptions(rt *libpod.Runtime, pod *libpod.P options = append(options, libpod.WithName(s.Name)) } if s.Pod != "" { + pod, err := rt.LookupPod(s.Pod) + if err != nil { + return nil, err + } logrus.Debugf("adding container to pod %s", s.Pod) options = append(options, rt.WithPod(pod)) } @@ -115,7 +119,6 @@ func (s *SpecGenerator) createContainerOptions(rt *libpod.Runtime, pod *libpod.P } options = append(options, namespaceOptions...) - // TODO NetworkNS still needs to be done! if len(s.ConmonPidFile) > 0 { options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile)) } diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go index 17b180cde..fa2dee77d 100644 --- a/pkg/specgen/namespaces.go +++ b/pkg/specgen/namespaces.go @@ -3,9 +3,9 @@ package specgen import ( "os" + "github.com/containers/common/pkg/capabilities" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/capabilities" "github.com/cri-o/ocicni/pkg/ocicni" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" @@ -70,9 +70,7 @@ func (n *Namespace) IsPrivate() bool { return n.NSMode == Private } -// validate perform simple validation on the namespace to make sure it is not -// invalid from the get-go -func (n *Namespace) validate() error { +func validateNetNS(n *Namespace) error { if n == nil { return nil } @@ -82,6 +80,15 @@ func (n *Namespace) validate() error { default: return errors.Errorf("invalid network %q", n.NSMode) } + return nil +} + +// validate perform simple validation on the namespace to make sure it is not +// invalid from the get-go +func (n *Namespace) validate() error { + if n == nil { + return nil + } // Path and From Container MUST have a string value set if n.NSMode == Path || n.NSMode == FromContainer { if len(n.Value) < 1 { diff --git a/pkg/specgen/validate.go b/pkg/specgen/validate.go index 78e4d8ad5..dd5ca3a55 100644 --- a/pkg/specgen/validate.go +++ b/pkg/specgen/validate.go @@ -138,7 +138,7 @@ func (s *SpecGenerator) validate(rt *libpod.Runtime) error { if err := s.IpcNS.validate(); err != nil { return err } - if err := s.NetNS.validate(); err != nil { + if err := validateNetNS(&s.NetNS); err != nil { return err } if err := s.PidNS.validate(); err != nil { diff --git a/pkg/systemd/generate/systemdgen.go b/pkg/systemd/generate/systemdgen.go index 404347828..4410e1395 100644 --- a/pkg/systemd/generate/systemdgen.go +++ b/pkg/systemd/generate/systemdgen.go @@ -80,6 +80,8 @@ const containerTemplate = `# {{.ServiceName}}.service [Unit] Description=Podman {{.ServiceName}}.service Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target {{- if .BoundToServices}} RefuseManualStart=yes RefuseManualStop=yes @@ -94,11 +96,11 @@ Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ [Service] Restart={{.RestartPolicy}} {{- if .New}} -ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid +ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid ExecStart={{.RunCommand}} -ExecStop={{.Executable}} stop --ignore --cidfile /%t/%n-cid {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} -ExecStopPost={{.Executable}} rm --ignore -f --cidfile /%t/%n-cid -PIDFile=/%t/%n-pid +ExecStop={{.Executable}} stop --ignore --cidfile %t/%n-cid {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} +ExecStopPost={{.Executable}} rm --ignore -f --cidfile %t/%n-cid +PIDFile=%t/%n-pid {{- else}} ExecStart={{.Executable}} start {{.ContainerName}} ExecStop={{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerName}} @@ -108,7 +110,7 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target` +WantedBy=multi-user.target default.target` // Options include different options to control the unit file generation. type Options struct { @@ -158,8 +160,8 @@ func CreateContainerSystemdUnit(info *ContainerInfo, opts Options) (string, erro command := []string{ info.Executable, "run", - "--conmon-pidfile", "/%t/%n-pid", - "--cidfile", "/%t/%n-cid", + "--conmon-pidfile", "%t/%n-pid", + "--cidfile", "%t/%n-cid", "--cgroups=no-conmon", } command = append(command, info.CreateCommand[index:]...) diff --git a/pkg/systemd/generate/systemdgen_test.go b/pkg/systemd/generate/systemdgen_test.go index b74b75258..3749d89ce 100644 --- a/pkg/systemd/generate/systemdgen_test.go +++ b/pkg/systemd/generate/systemdgen_test.go @@ -40,6 +40,8 @@ func TestCreateContainerSystemdUnit(t *testing.T) { [Unit] Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target [Service] Restart=always @@ -50,7 +52,7 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target` +WantedBy=multi-user.target default.target` goodName := `# container-foobar.service # autogenerated by Podman CI @@ -58,6 +60,8 @@ WantedBy=multi-user.target` [Unit] Description=Podman container-foobar.service Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target [Service] Restart=always @@ -68,7 +72,7 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target` +WantedBy=multi-user.target default.target` goodNameBoundTo := `# container-foobar.service # autogenerated by Podman CI @@ -76,6 +80,8 @@ WantedBy=multi-user.target` [Unit] Description=Podman container-foobar.service Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target RefuseManualStart=yes RefuseManualStop=yes BindsTo=a.service b.service c.service pod.service @@ -90,7 +96,7 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target` +WantedBy=multi-user.target default.target` podGoodName := `# pod-123abc.service # autogenerated by Podman CI @@ -98,6 +104,8 @@ WantedBy=multi-user.target` [Unit] Description=Podman pod-123abc.service Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target Requires=container-1.service container-2.service Before=container-1.service container-2.service @@ -110,7 +118,7 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target` +WantedBy=multi-user.target default.target` goodNameNew := `# jadda-jadda.service # autogenerated by Podman CI @@ -118,19 +126,21 @@ WantedBy=multi-user.target` [Unit] Description=Podman jadda-jadda.service Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target [Service] Restart=always -ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid -ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile /%t/%n-cid --cgroups=no-conmon --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN -ExecStop=/usr/bin/podman stop --ignore --cidfile /%t/%n-cid -t 42 -ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile /%t/%n-cid -PIDFile=/%t/%n-pid +ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid +ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 42 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid +PIDFile=%t/%n-pid KillMode=none Type=forking [Install] -WantedBy=multi-user.target` +WantedBy=multi-user.target default.target` tests := []struct { name string diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 4a52ea68d..a4df48c88 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -600,3 +600,12 @@ func HomeDir() (string, error) { } return home, nil } + +func Tmpdir() string { + tmpdir := os.Getenv("TMPDIR") + if tmpdir == "" { + tmpdir = "/var/tmp" + } + + return tmpdir +} |