summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers.go15
-rw-r--r--pkg/api/handlers/compat/containers_create.go21
-rw-r--r--pkg/api/handlers/compat/info.go3
-rw-r--r--pkg/api/handlers/compat/ping.go3
-rw-r--r--pkg/api/handlers/libpod/containers.go24
-rw-r--r--pkg/api/handlers/libpod/images.go6
-rw-r--r--pkg/api/handlers/libpod/images_pull.go3
-rw-r--r--pkg/api/handlers/types.go13
-rw-r--r--pkg/api/handlers/utils/containers.go18
-rw-r--r--pkg/api/server/handler_api.go7
-rw-r--r--pkg/api/server/listener_api.go1
-rw-r--r--pkg/api/server/register_ping.go2
-rw-r--r--pkg/api/server/server.go6
-rw-r--r--pkg/bindings/containers/containers.go12
-rw-r--r--pkg/domain/entities/container_ps.go5
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/entities/images.go8
-rw-r--r--pkg/domain/infra/abi/containers.go15
-rw-r--r--pkg/domain/infra/abi/play.go67
-rw-r--r--pkg/domain/infra/abi/system_novalink.go14
-rw-r--r--pkg/domain/infra/abi/system_varlink.go49
-rw-r--r--pkg/domain/infra/tunnel/containers.go27
-rw-r--r--pkg/domain/infra/tunnel/images.go4
-rw-r--r--pkg/domain/infra/tunnel/system.go4
-rw-r--r--pkg/ps/ps.go6
-rw-r--r--pkg/spec/config_linux.go371
-rw-r--r--pkg/spec/config_linux_cgo.go47
-rw-r--r--pkg/spec/config_linux_nocgo.go11
-rw-r--r--pkg/spec/config_unsupported.go36
-rw-r--r--pkg/spec/containerconfig.go41
-rw-r--r--pkg/spec/createconfig.go426
-rw-r--r--pkg/spec/namespaces.go463
-rw-r--r--pkg/spec/parse.go225
-rw-r--r--pkg/spec/ports.go107
-rw-r--r--pkg/spec/security.go204
-rw-r--r--pkg/spec/spec.go593
-rw-r--r--pkg/spec/spec_test.go108
-rw-r--r--pkg/spec/storage.go875
-rw-r--r--pkg/spec/storage_test.go38
-rw-r--r--pkg/specgen/generate/container.go14
-rw-r--r--pkg/specgen/generate/container_create.go12
-rw-r--r--pkg/specgen/generate/kube/kube.go40
-rw-r--r--pkg/specgen/generate/kube/volume.go124
-rw-r--r--pkg/specgen/generate/storage.go61
-rw-r--r--pkg/specgen/namespaces.go16
-rw-r--r--pkg/specgen/specgen.go38
-rw-r--r--pkg/specgen/volumes.go149
-rw-r--r--pkg/varlink/generate.go3
-rw-r--r--pkg/varlink/io.podman.varlink1398
-rw-r--r--pkg/varlinkapi/attach.go144
-rw-r--r--pkg/varlinkapi/config.go22
-rw-r--r--pkg/varlinkapi/container.go928
-rw-r--r--pkg/varlinkapi/containers.go912
-rw-r--r--pkg/varlinkapi/containers_create.go17
-rw-r--r--pkg/varlinkapi/create.go1155
-rw-r--r--pkg/varlinkapi/events.go56
-rw-r--r--pkg/varlinkapi/funcs.go121
-rw-r--r--pkg/varlinkapi/generate.go30
-rw-r--r--pkg/varlinkapi/images.go1037
-rw-r--r--pkg/varlinkapi/intermediate.go289
-rw-r--r--pkg/varlinkapi/intermediate_varlink.go457
-rw-r--r--pkg/varlinkapi/mount.go49
-rw-r--r--pkg/varlinkapi/pods.go389
-rw-r--r--pkg/varlinkapi/remote_client.go29
-rw-r--r--pkg/varlinkapi/shortcuts.go66
-rw-r--r--pkg/varlinkapi/system.go129
-rw-r--r--pkg/varlinkapi/transfers.go80
-rw-r--r--pkg/varlinkapi/util.go237
-rw-r--r--pkg/varlinkapi/virtwriter/virtwriter.go204
-rw-r--r--pkg/varlinkapi/volumes.go165
70 files changed, 510 insertions, 11740 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 00be8e845..5886455e7 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -298,6 +298,9 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
state.Running = true
}
+ formatCapabilities(inspect.HostConfig.CapDrop)
+ formatCapabilities(inspect.HostConfig.CapAdd)
+
h, err := json.Marshal(inspect.HostConfig)
if err != nil {
return nil, err
@@ -318,8 +321,8 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
cb := types.ContainerJSONBase{
ID: l.ID(),
Created: l.CreatedTime().Format(time.RFC3339Nano),
- Path: "",
- Args: nil,
+ Path: inspect.Path,
+ Args: inspect.Args,
State: &state,
Image: imageName,
ResolvConfPath: inspect.ResolvConfPath,
@@ -328,7 +331,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
LogPath: l.LogPath(),
Node: nil,
Name: fmt.Sprintf("/%s", l.Name()),
- RestartCount: 0,
+ RestartCount: int(inspect.RestartCount),
Driver: inspect.Driver,
Platform: "linux",
MountLabel: inspect.MountLabel,
@@ -428,3 +431,9 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
}
return &c, nil
}
+
+func formatCapabilities(slice []string) {
+ for i := range slice {
+ slice[i] = strings.TrimPrefix(slice[i], "CAP_")
+ }
+}
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 4efe770b3..729639928 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -19,7 +19,6 @@ import (
func CreateContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
- input := handlers.CreateContainerConfig{}
query := struct {
Name string `schema:"name"`
}{
@@ -30,11 +29,15 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
+
+ // compatible configuration
+ body := handlers.CreateContainerConfig{}
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
- if len(input.HostConfig.Links) > 0 {
+
+ if len(body.HostConfig.Links) > 0 {
utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
return
}
@@ -43,7 +46,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "unable to obtain runtime config", http.StatusInternalServerError, errors.Wrap(err, "unable to get runtime config"))
}
- newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
+ newImage, err := runtime.ImageRuntime().NewFromLocal(body.Config.Image)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchImage {
utils.Error(w, "No such image", http.StatusNotFound, err)
@@ -54,11 +57,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
return
}
- // Add the container name to the input struct
- input.Name = query.Name
-
- // Take input structure and convert to cliopts
- cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(input, rtc.Engine.CgroupManager)
+ // Take body structure and convert to cliopts
+ cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(body, rtc.Engine.CgroupManager)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
return
@@ -69,6 +69,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
return
}
+ // Override the container name in the body struct
+ body.Name = query.Name
+
ic := abi.ContainerEngine{Libpod: runtime}
report, err := ic.ContainerCreate(r.Context(), sg)
if err != nil {
diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go
index 2bb165522..4b3a390f1 100644
--- a/pkg/api/handlers/compat/info.go
+++ b/pkg/api/handlers/compat/info.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/rootless"
docker "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/google/uuid"
"github.com/pkg/errors"
@@ -103,7 +104,7 @@ func GetInfo(w http.ResponseWriter, r *http.Request) {
PidsLimit: sysInfo.PidsLimit,
Plugins: docker.PluginsInfo{},
ProductLicense: "Apache-2.0",
- RegistryConfig: nil,
+ RegistryConfig: new(registry.ServiceConfig),
RuncCommit: docker.Commit{},
Runtimes: getRuntimes(configInfo),
SecurityOptions: getSecOpts(sysInfo),
diff --git a/pkg/api/handlers/compat/ping.go b/pkg/api/handlers/compat/ping.go
index 06150bb63..9f6611b30 100644
--- a/pkg/api/handlers/compat/ping.go
+++ b/pkg/api/handlers/compat/ping.go
@@ -19,11 +19,10 @@ func Ping(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Pragma", "no-cache")
- w.Header().Set("Libpod-Buildha-Version", buildah.Version)
+ w.Header().Set("Libpod-Buildah-Version", buildah.Version)
w.WriteHeader(http.StatusOK)
if r.Method == http.MethodGet {
fmt.Fprint(w, "OK")
}
- fmt.Fprint(w, "\n")
}
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 7e6481321..14eb44831 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -344,3 +344,27 @@ func InitContainer(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusNoContent, "")
}
+
+func ShouldRestart(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
+ name := utils.GetName(r)
+ report, err := containerEngine.ShouldRestart(r.Context(), name)
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ utils.InternalServerError(w, err)
+ return
+
+ }
+ if report.Value {
+ utils.WriteResponse(w, http.StatusNoContent, "")
+ } else {
+ utils.ContainerNotFound(w, name, define.ErrNoSuchCtr)
+ }
+}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 55264b3b6..be5a394de 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -422,8 +422,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
source := strings.TrimSuffix(utils.GetName(r), "/push") // GetName returns the entire path
if _, err := utils.ParseStorageReference(source); err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "image source %q is not a containers-storage-transport reference", source))
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
@@ -433,8 +432,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
}
if _, err := utils.ParseDockerReference(destination); err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "image destination %q is not a docker-transport reference", destination))
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index 05e4b8258..5e2727e95 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -53,8 +53,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
imageRef, err := utils.ParseDockerReference(query.Reference)
if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "image destination %q is not a docker-transport reference", query.Reference))
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 6bb5f5101..40cf16807 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -110,11 +110,12 @@ type ContainerWaitOKBody struct {
}
}
+// CreateContainerConfig used when compatible endpoint creates a container
type CreateContainerConfig struct {
- Name string
- dockerContainer.Config
- HostConfig dockerContainer.HostConfig
- NetworkingConfig dockerNetwork.NetworkingConfig
+ Name string // container name
+ dockerContainer.Config // desired container configuration
+ HostConfig dockerContainer.HostConfig // host dependent configuration for container
+ NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container
}
// swagger:model IDResponse
@@ -253,7 +254,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
// StdinOnce: false,
Env: info.Config.Env,
Cmd: info.Config.Cmd,
- //Healthcheck: l.ImageData.HealthCheck,
+ // Healthcheck: l.ImageData.HealthCheck,
// ArgsEscaped: false,
// Image: "",
Volumes: info.Config.Volumes,
@@ -261,7 +262,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
Entrypoint: info.Config.Entrypoint,
// NetworkDisabled: false,
// MacAddress: "",
- //OnBuild: info.Config.OnBuild,
+ // OnBuild: info.Config.OnBuild,
Labels: info.Labels,
StopSignal: info.Config.StopSignal,
// StopTimeout: nil,
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index 185b724fc..1439a3a75 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -1,14 +1,11 @@
package utils
import (
- "context"
"net/http"
"time"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/domain/entities"
- createconfig "github.com/containers/podman/v2/pkg/spec"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -59,18 +56,3 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
}
return con.WaitForConditionWithInterval(interval, condition)
}
-
-func CreateContainer(ctx context.Context, w http.ResponseWriter, runtime *libpod.Runtime, cc *createconfig.CreateConfig) {
- var pod *libpod.Pod
- ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, runtime, cc, pod)
- if err != nil {
- Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "CreateContainerFromCreateConfig()"))
- return
- }
-
- response := entities.ContainerCreateResponse{
- ID: ctr.ID(),
- Warnings: []string{}}
-
- WriteResponse(w, http.StatusCreated, response)
-}
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index 28f5a0b42..1d0ddb457 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -30,14 +30,14 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
// Wrapper to hide some boiler plate
fn := func(w http.ResponseWriter, r *http.Request) {
rid := uuid.New().String()
+ logrus.Infof("APIHandler(%s) -- %s %s BEGIN", rid, r.Method, r.URL.String())
if logrus.IsLevelEnabled(logrus.DebugLevel) {
- logrus.Debugf("APIHandler(%s) -- Method: %s URL: %s", rid, r.Method, r.URL.String())
for k, v := range r.Header {
switch auth.HeaderAuthName(k) {
case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
- logrus.Debugf("APIHandler(%s) -- Header: %s: <hidden>", rid, k)
+ logrus.Debugf("APIHandler(%s) -- Header: %s=<hidden>", rid, k)
default:
- logrus.Debugf("APIHandler(%s) -- Header: %s: %v", rid, k, v)
+ logrus.Debugf("APIHandler(%s) -- Header: %s=%v", rid, k, v)
}
}
}
@@ -63,6 +63,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
h(w, r)
+ logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String())
}
fn(w, r)
}
diff --git a/pkg/api/server/listener_api.go b/pkg/api/server/listener_api.go
index 4984216b8..2d02df7dc 100644
--- a/pkg/api/server/listener_api.go
+++ b/pkg/api/server/listener_api.go
@@ -27,5 +27,6 @@ func ListenUnix(network string, path string) (net.Listener, error) {
if err != nil {
return nil, errors.Wrapf(err, "net.Listen(%s, %s) failed to report the failure to create socket", network, path)
}
+
return listener, nil
}
diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go
index 4e299008c..446a12a68 100644
--- a/pkg/api/server/register_ping.go
+++ b/pkg/api/server/register_ping.go
@@ -53,7 +53,7 @@ func (s *APIServer) registerPingHandlers(r *mux.Router) error {
// Max Podman API Version the server supports.
// Available if service is backed by Podman, therefore may be used to
// determine if talking to Podman engine or another engine
- // Libpod-Buildha-Version:
+ // Libpod-Buildah-Version:
// type: string
// description: |
// Default version of libpod image builder.
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 64008767b..09b6079e4 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -51,10 +51,7 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
}
// NewServerWithSettings will create and configure a new API server using provided settings
-func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (
- *APIServer,
- error,
-) {
+func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
return newServer(runtime, duration, listener)
}
@@ -75,6 +72,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
listener = &listeners[0]
}
+ logrus.Infof("API server listening on %q", (*listener).Addr())
router := mux.NewRouter().UseEncodedPath()
idle := idle.NewTracker(duration)
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index b5cd2128b..4331ae6c2 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -390,3 +390,15 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
}
return response.Process(nil)
}
+
+func ShouldRestart(ctx context.Context, nameOrID string) (bool, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return false, err
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/shouldrestart", nil, nil, nameOrID)
+ if err != nil {
+ return false, err
+ }
+ return response.IsSuccess(), nil
+}
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index ed40a37ab..b4e8446cb 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -3,6 +3,7 @@ package entities
import (
"sort"
"strings"
+ "time"
"github.com/containers/podman/v2/pkg/ps/define"
"github.com/cri-o/ocicni/pkg/ocicni"
@@ -14,7 +15,7 @@ type ListContainer struct {
// Container command
Command []string
// Container creation time
- Created int64
+ Created time.Time
// Human readable container creation time.
CreatedAt string
// If container has exited/stopped
@@ -137,7 +138,7 @@ func (a psSortedSize) Less(i, j int) bool {
type PsSortedCreateTime struct{ SortListContainers }
func (a PsSortedCreateTime) Less(i, j int) bool {
- return a.SortListContainers[i].Created < a.SortListContainers[j].Created
+ return a.SortListContainers[i].Created.Before(a.SortListContainers[j].Created)
}
func SortPsOutput(sortBy string, psOutput SortListContainers) (SortListContainers, error) {
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index b051d3eec..df7da616a 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -75,7 +75,6 @@ type ContainerEngine interface {
Shutdown(ctx context.Context)
SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error)
Unshare(ctx context.Context, args []string) error
- VarlinkService(ctx context.Context, opts ServiceOptions) error
Version(ctx context.Context) (*SystemVersionReport, error)
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 101542a98..ab545d882 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -51,10 +51,10 @@ func (i *Image) Id() string { // nolint
}
type ImageSummary struct {
- ID string `json:"Id"`
- ParentId string `json:",omitempty"` // nolint
- RepoTags []string `json:",omitempty"`
- Created int64 `json:",omitempty"`
+ ID string `json:"Id"`
+ ParentId string // nolint
+ RepoTags []string `json:",omitempty"`
+ Created int64
Size int64 `json:",omitempty"`
SharedSize int `json:",omitempty"`
VirtualSize int64 `json:",omitempty"`
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 4b69ac74e..ff4277a2e 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -911,7 +911,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
} else {
report.ExitCode = int(ecode)
}
- if opts.Rm {
+ if opts.Rm && !ctr.ShouldRestart(ctx) {
if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr ||
errors.Cause(err) == define.ErrCtrRemoved {
@@ -992,7 +992,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
return []*entities.ContainerCleanupReport{}, nil
}
- if options.Remove {
+ if options.Remove && !ctr.ShouldRestart(ctx) {
err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
if err != nil {
report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
@@ -1015,6 +1015,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
report.RmiErr = err
}
+
reports = append(reports, &report)
}
return reports, nil
@@ -1314,3 +1315,13 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
return statsChan, nil
}
+
+// ShouldRestart returns whether the container should be restarted
+func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
+}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 4bcc6469c..3aeb6a2ee 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -8,7 +8,6 @@ import (
"os"
"strings"
- "github.com/containers/buildah/pkg/parse"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/image"
@@ -24,13 +23,6 @@ import (
v1 "k8s.io/api/core/v1"
)
-const (
- // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
- kubeDirectoryPermission = 0755
- // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
- kubeFilePermission = 0644
-)
-
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
var (
kubeObject v1.ObjectReference
@@ -168,62 +160,9 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
}
- // map from name to mount point
- volumes := make(map[string]string)
- for _, volume := range podYAML.Spec.Volumes {
- hostPath := volume.VolumeSource.HostPath
- if hostPath == nil {
- return nil, errors.Errorf("HostPath is currently the only supported VolumeSource")
- }
- if hostPath.Type != nil {
- switch *hostPath.Type {
- case v1.HostPathDirectoryOrCreate:
- if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
- if err := os.Mkdir(hostPath.Path, kubeDirectoryPermission); err != nil {
- return nil, err
- }
- }
- // Label a newly created volume
- if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
- return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path)
- }
- case v1.HostPathFileOrCreate:
- if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
- f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission)
- if err != nil {
- return nil, errors.Wrap(err, "error creating HostPath")
- }
- if err := f.Close(); err != nil {
- logrus.Warnf("Error in closing newly created HostPath file: %v", err)
- }
- }
- // unconditionally label a newly created volume
- if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
- return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path)
- }
- case v1.HostPathSocket:
- st, err := os.Stat(hostPath.Path)
- if err != nil {
- return nil, errors.Wrap(err, "error checking HostPathSocket")
- }
- if st.Mode()&os.ModeSocket != os.ModeSocket {
- return nil, errors.Errorf("error checking HostPathSocket: path %s is not a socket", hostPath.Path)
- }
-
- case v1.HostPathDirectory:
- case v1.HostPathFile:
- case v1.HostPathUnset:
- // do nothing here because we will verify the path exists in validateVolumeHostDir
- break
- default:
- return nil, errors.Errorf("Invalid HostPath type %v", hostPath.Type)
- }
- }
-
- if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil {
- return nil, errors.Wrapf(err, "error in parsing HostPath in YAML")
- }
- volumes[volume.Name] = hostPath.Path
+ volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes)
+ if err != nil {
+ return nil, err
}
seccompPaths, err := kube.InitializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot)
diff --git a/pkg/domain/infra/abi/system_novalink.go b/pkg/domain/infra/abi/system_novalink.go
deleted file mode 100644
index 3518e9db6..000000000
--- a/pkg/domain/infra/abi/system_novalink.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build !varlink
-
-package abi
-
-import (
- "context"
-
- "github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/pkg/errors"
-)
-
-func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error {
- return errors.Errorf("varlink is not supported")
-}
diff --git a/pkg/domain/infra/abi/system_varlink.go b/pkg/domain/infra/abi/system_varlink.go
deleted file mode 100644
index ead84fc84..000000000
--- a/pkg/domain/infra/abi/system_varlink.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// +build varlink
-
-package abi
-
-import (
- "context"
-
- "github.com/containers/podman/v2/pkg/domain/entities"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- iopodmanAPI "github.com/containers/podman/v2/pkg/varlinkapi"
- "github.com/containers/podman/v2/version"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "github.com/varlink/go/varlink"
-)
-
-func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error {
- var varlinkInterfaces = []*iopodman.VarlinkInterface{
- iopodmanAPI.New(opts.Command, ic.Libpod),
- }
-
- service, err := varlink.NewService(
- "Atomic",
- "podman",
- version.Version.String(),
- "https://github.com/containers/podman",
- )
- if err != nil {
- return errors.Wrapf(err, "unable to create new varlink service")
- }
-
- for _, i := range varlinkInterfaces {
- if err := service.RegisterInterface(i); err != nil {
- return errors.Errorf("unable to register varlink interface %v", i)
- }
- }
-
- // Run the varlink server at the given address
- if err = service.Listen(opts.URI, opts.Timeout); err != nil {
- switch err.(type) {
- case varlink.ServiceTimeoutError:
- logrus.Infof("varlink service expired (use --time to increase session time beyond %s ms, 0 means never timeout)", opts.Timeout.String())
- return nil
- default:
- return errors.Wrapf(err, "unable to start varlink service")
- }
- }
- return nil
-}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 8066e1c00..63677719b 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -235,7 +235,7 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
if len(options.ImageName) > 0 {
ref, err := reference.Parse(options.ImageName)
if err != nil {
- return nil, err
+ return nil, errors.Wrapf(err, "error parsing reference %q", options.ImageName)
}
if t, ok := ref.(reference.Tagged); ok {
tag = t.Tag()
@@ -595,12 +595,20 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Defer the removal, so we can return early if needed and
// de-spaghetti the code.
defer func() {
- if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
- if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
- errorhandling.Contains(err, define.ErrCtrRemoved) {
- logrus.Warnf("Container %s does not exist: %v", con.ID, err)
- } else {
- logrus.Errorf("Error removing container %s: %v", con.ID, err)
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCxt, con.ID)
+ if err != nil {
+ logrus.Errorf("Failed to check if %s should restart: %v", con.ID, err)
+ return
+ }
+
+ if !shouldRestart {
+ if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", con.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", con.ID, err)
+ }
}
}
}()
@@ -737,3 +745,8 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
}
return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
}
+
+// ShouldRestart reports back whether the containre will restart
+func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
+ return containers.ShouldRestart(ic.ClientCxt, id)
+}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 61ac2141c..09931de12 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -119,7 +119,7 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
)
ref, err := reference.Parse(newTag)
if err != nil {
- return err
+ return errors.Wrapf(err, "error parsing reference %q", newTag)
}
if t, ok := ref.(reference.Tagged); ok {
tag = t.Tag()
@@ -148,7 +148,7 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
)
ref, err := reference.Parse(newTag)
if err != nil {
- return err
+ return errors.Wrapf(err, "error parsing reference %q", newTag)
}
if t, ok := ref.(reference.Tagged); ok {
tag = t.Tag()
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index c276e15c5..f3e8fbcb1 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -14,10 +14,6 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
return system.Info(ic.ClientCxt)
}
-func (ic *ContainerEngine) VarlinkService(_ context.Context, _ entities.ServiceOptions) error {
- panic(errors.New("varlink service is not supported when tunneling"))
-}
-
func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
panic(errors.New("rootless engine mode is not supported when tunneling"))
}
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index 3dd7eb0c6..cfdf3ee49 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -180,7 +180,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
ps := entities.ListContainer{
Command: conConfig.Command,
- Created: conConfig.CreatedTime.Unix(),
+ Created: conConfig.CreatedTime,
Exited: exited,
ExitCode: exitCode,
ExitedAt: exitedTime.Unix(),
@@ -231,7 +231,7 @@ func ListStorageContainer(rt *libpod.Runtime, ctr storage.Container, opts entiti
ps := entities.ListContainer{
ID: ctr.ID,
- Created: ctr.Created.Unix(),
+ Created: ctr.Created,
ImageID: ctr.ImageID,
State: "storage",
Names: []string{name},
@@ -301,5 +301,5 @@ func (a SortPSContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type SortPSCreateTime struct{ SortPSContainers }
func (a SortPSCreateTime) Less(i, j int) bool {
- return a.SortPSContainers[i].Created > a.SortPSContainers[j].Created
+ return a.SortPSContainers[i].Created.Before(a.SortPSContainers[j].Created)
}
diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go
deleted file mode 100644
index 319cce61f..000000000
--- a/pkg/spec/config_linux.go
+++ /dev/null
@@ -1,371 +0,0 @@
-// +build linux
-
-package createconfig
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/containers/podman/v2/pkg/rootless"
- "github.com/opencontainers/runc/libcontainer/configs"
- "github.com/opencontainers/runc/libcontainer/devices"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
-)
-
-// Device transforms a libcontainer configs.Device to a specs.LinuxDevice object.
-func Device(d *configs.Device) spec.LinuxDevice {
- return spec.LinuxDevice{
- Type: string(d.Type),
- Path: d.Path,
- Major: d.Major,
- Minor: d.Minor,
- FileMode: fmPtr(int64(d.FileMode)),
- UID: u32Ptr(int64(d.Uid)),
- GID: u32Ptr(int64(d.Gid)),
- }
-}
-
-// DevicesFromPath computes a list of devices
-func DevicesFromPath(g *generate.Generator, devicePath string) error {
- devs := strings.Split(devicePath, ":")
- resolvedDevicePath := devs[0]
- // check if it is a symbolic link
- if src, err := os.Lstat(resolvedDevicePath); err == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
- if linkedPathOnHost, err := filepath.EvalSymlinks(resolvedDevicePath); err == nil {
- resolvedDevicePath = linkedPathOnHost
- }
- }
- st, err := os.Stat(resolvedDevicePath)
- if err != nil {
- return errors.Wrapf(err, "cannot stat %s", devicePath)
- }
- if st.IsDir() {
- found := false
- src := resolvedDevicePath
- dest := src
- var devmode string
- if len(devs) > 1 {
- if len(devs[1]) > 0 && devs[1][0] == '/' {
- dest = devs[1]
- } else {
- devmode = devs[1]
- }
- }
- if len(devs) > 2 {
- if devmode != "" {
- return errors.Wrapf(unix.EINVAL, "invalid device specification %s", devicePath)
- }
- devmode = devs[2]
- }
-
- // mount the internal devices recursively
- if err := filepath.Walk(resolvedDevicePath, func(dpath string, f os.FileInfo, e error) error {
-
- if f.Mode()&os.ModeDevice == os.ModeDevice {
- found = true
- device := fmt.Sprintf("%s:%s", dpath, filepath.Join(dest, strings.TrimPrefix(dpath, src)))
- if devmode != "" {
- device = fmt.Sprintf("%s:%s", device, devmode)
- }
- if err := addDevice(g, device); err != nil {
- return errors.Wrapf(err, "failed to add %s device", dpath)
- }
- }
- return nil
- }); err != nil {
- return err
- }
- if !found {
- return errors.Wrapf(unix.EINVAL, "no devices found in %s", devicePath)
- }
- return nil
- }
-
- return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":"))
-}
-
-func deviceCgroupRules(g *generate.Generator, deviceCgroupRules []string) error {
- for _, deviceCgroupRule := range deviceCgroupRules {
- if err := validateDeviceCgroupRule(deviceCgroupRule); err != nil {
- return err
- }
- ss := parseDeviceCgroupRule(deviceCgroupRule)
- if len(ss[0]) != 5 {
- return errors.Errorf("invalid device cgroup rule format: '%s'", deviceCgroupRule)
- }
- matches := ss[0]
- var major, minor *int64
- if matches[2] == "*" {
- majorDev := int64(-1)
- major = &majorDev
- } else {
- majorDev, err := strconv.ParseInt(matches[2], 10, 64)
- if err != nil {
- return errors.Errorf("invalid major value in device cgroup rule format: '%s'", deviceCgroupRule)
- }
- major = &majorDev
- }
- if matches[3] == "*" {
- minorDev := int64(-1)
- minor = &minorDev
- } else {
- minorDev, err := strconv.ParseInt(matches[2], 10, 64)
- if err != nil {
- return errors.Errorf("invalid major value in device cgroup rule format: '%s'", deviceCgroupRule)
- }
- minor = &minorDev
- }
- g.AddLinuxResourcesDevice(true, matches[1], major, minor, matches[4])
- }
- return nil
-}
-
-func addDevice(g *generate.Generator, device string) error {
- src, dst, permissions, err := ParseDevice(device)
- if err != nil {
- return err
- }
- dev, err := devices.DeviceFromPath(src, permissions)
- if err != nil {
- return errors.Wrapf(err, "%s is not a valid device", src)
- }
- if rootless.IsRootless() {
- if _, err := os.Stat(src); err != nil {
- if os.IsNotExist(err) {
- return errors.Wrapf(err, "the specified device %s doesn't exist", src)
- }
- return errors.Wrapf(err, "stat device %s exist", src)
- }
- perm := "ro"
- if strings.Contains(permissions, "w") {
- perm = "rw"
- }
- devMnt := spec.Mount{
- Destination: dst,
- Type: TypeBind,
- Source: src,
- Options: []string{"slave", "nosuid", "noexec", perm, "rbind"},
- }
- g.Config.Mounts = append(g.Config.Mounts, devMnt)
- return nil
- }
- dev.Path = dst
- linuxdev := spec.LinuxDevice{
- Path: dev.Path,
- Type: string(dev.Type),
- Major: dev.Major,
- Minor: dev.Minor,
- FileMode: &dev.FileMode,
- UID: &dev.Uid,
- GID: &dev.Gid,
- }
- g.AddDevice(linuxdev)
- g.AddLinuxResourcesDevice(true, string(dev.Type), &dev.Major, &dev.Minor, string(dev.Permissions))
- return nil
-}
-
-// based on getDevices from runc (libcontainer/devices/devices.go)
-func getDevices(path string) ([]*configs.Device, error) {
- files, err := ioutil.ReadDir(path)
- if err != nil {
- if rootless.IsRootless() && os.IsPermission(err) {
- return nil, nil
- }
- return nil, err
- }
- out := []*configs.Device{}
- for _, f := range files {
- switch {
- case f.IsDir():
- switch f.Name() {
- // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
- case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
- continue
- default:
- sub, err := getDevices(filepath.Join(path, f.Name()))
- if err != nil {
- return nil, err
- }
- if sub != nil {
- out = append(out, sub...)
- }
- continue
- }
- case f.Name() == "console":
- continue
- case f.Mode()&os.ModeSymlink != 0:
- // do not add symlink'd devices to privileged devices
- continue
- }
- device, err := devices.DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
- if err != nil {
- if err == devices.ErrNotADevice {
- continue
- }
- if os.IsNotExist(err) {
- continue
- }
- return nil, err
- }
- out = append(out, device)
- }
- return out, nil
-}
-
-func addPrivilegedDevices(g *generate.Generator) error {
- hostDevices, err := getDevices("/dev")
- if err != nil {
- return err
- }
- g.ClearLinuxDevices()
-
- if rootless.IsRootless() {
- mounts := make(map[string]interface{})
- for _, m := range g.Mounts() {
- mounts[m.Destination] = true
- }
- newMounts := []spec.Mount{}
- for _, d := range hostDevices {
- devMnt := spec.Mount{
- Destination: d.Path,
- Type: TypeBind,
- Source: d.Path,
- Options: []string{"slave", "nosuid", "noexec", "rw", "rbind"},
- }
- if d.Path == "/dev/ptmx" || strings.HasPrefix(d.Path, "/dev/tty") {
- continue
- }
- if _, found := mounts[d.Path]; found {
- continue
- }
- st, err := os.Stat(d.Path)
- if err != nil {
- if err == unix.EPERM {
- continue
- }
- return errors.Wrapf(err, "stat %s", d.Path)
- }
- // Skip devices that the user has not access to.
- if st.Mode()&0007 == 0 {
- continue
- }
- newMounts = append(newMounts, devMnt)
- }
- g.Config.Mounts = append(newMounts, g.Config.Mounts...)
- g.Config.Linux.Resources.Devices = nil
- } else {
- for _, d := range hostDevices {
- g.AddDevice(Device(d))
- }
- // Add resources device - need to clear the existing one first.
- g.Config.Linux.Resources.Devices = nil
- g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
- }
-
- return nil
-}
-
-func (c *CreateConfig) createBlockIO() (*spec.LinuxBlockIO, error) {
- var ret *spec.LinuxBlockIO
- bio := &spec.LinuxBlockIO{}
- if c.Resources.BlkioWeight > 0 {
- ret = bio
- bio.Weight = &c.Resources.BlkioWeight
- }
- if len(c.Resources.BlkioWeightDevice) > 0 {
- var lwds []spec.LinuxWeightDevice
- ret = bio
- for _, i := range c.Resources.BlkioWeightDevice {
- wd, err := ValidateweightDevice(i)
- if err != nil {
- return ret, errors.Wrapf(err, "invalid values for blkio-weight-device")
- }
- wdStat, err := GetStatFromPath(wd.Path)
- if err != nil {
- return ret, errors.Wrapf(err, "error getting stat from path %q", wd.Path)
- }
- lwd := spec.LinuxWeightDevice{
- Weight: &wd.Weight,
- }
- lwd.Major = int64(unix.Major(wdStat.Rdev))
- lwd.Minor = int64(unix.Minor(wdStat.Rdev))
- lwds = append(lwds, lwd)
- }
- bio.WeightDevice = lwds
- }
- if len(c.Resources.DeviceReadBps) > 0 {
- ret = bio
- readBps, err := makeThrottleArray(c.Resources.DeviceReadBps, bps)
- if err != nil {
- return ret, err
- }
- bio.ThrottleReadBpsDevice = readBps
- }
- if len(c.Resources.DeviceWriteBps) > 0 {
- ret = bio
- writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps, bps)
- if err != nil {
- return ret, err
- }
- bio.ThrottleWriteBpsDevice = writeBpds
- }
- if len(c.Resources.DeviceReadIOps) > 0 {
- ret = bio
- readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps, iops)
- if err != nil {
- return ret, err
- }
- bio.ThrottleReadIOPSDevice = readIOps
- }
- if len(c.Resources.DeviceWriteIOps) > 0 {
- ret = bio
- writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps, iops)
- if err != nil {
- return ret, err
- }
- bio.ThrottleWriteIOPSDevice = writeIOps
- }
- return ret, nil
-}
-
-func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) {
- var (
- ltds []spec.LinuxThrottleDevice
- t *throttleDevice
- err error
- )
- for _, i := range throttleInput {
- if rateType == bps {
- t, err = validateBpsDevice(i)
- } else {
- t, err = validateIOpsDevice(i)
- }
- if err != nil {
- return []spec.LinuxThrottleDevice{}, err
- }
- ltdStat, err := GetStatFromPath(t.path)
- if err != nil {
- return ltds, errors.Wrapf(err, "error getting stat from path %q", t.path)
- }
- ltd := spec.LinuxThrottleDevice{
- Rate: t.rate,
- }
- ltd.Major = int64(unix.Major(ltdStat.Rdev))
- ltd.Minor = int64(unix.Minor(ltdStat.Rdev))
- ltds = append(ltds, ltd)
- }
- return ltds, nil
-}
-
-func GetStatFromPath(path string) (unix.Stat_t, error) {
- s := unix.Stat_t{}
- err := unix.Stat(path, &s)
- return s, err
-}
diff --git a/pkg/spec/config_linux_cgo.go b/pkg/spec/config_linux_cgo.go
deleted file mode 100644
index d0891b574..000000000
--- a/pkg/spec/config_linux_cgo.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// +build linux,cgo
-
-package createconfig
-
-import (
- "io/ioutil"
-
- goSeccomp "github.com/containers/common/pkg/seccomp"
- "github.com/containers/podman/v2/pkg/seccomp"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
- var seccompConfig *spec.LinuxSeccomp
- var err error
-
- if config.SeccompPolicy == seccomp.PolicyImage && config.SeccompProfileFromImage != "" {
- logrus.Debug("Loading seccomp profile from the security config")
- seccompConfig, err = goSeccomp.LoadProfile(config.SeccompProfileFromImage, configSpec)
- if err != nil {
- return nil, errors.Wrap(err, "loading seccomp profile failed")
- }
- return seccompConfig, nil
- }
-
- if config.SeccompProfilePath != "" {
- logrus.Debugf("Loading seccomp profile from %q", config.SeccompProfilePath)
- seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath)
- if err != nil {
- return nil, errors.Wrap(err, "opening seccomp profile failed")
- }
- seccompConfig, err = goSeccomp.LoadProfile(string(seccompProfile), configSpec)
- if err != nil {
- return nil, errors.Wrapf(err, "loading seccomp profile (%s) failed", config.SeccompProfilePath)
- }
- } else {
- logrus.Debug("Loading default seccomp profile")
- seccompConfig, err = goSeccomp.GetDefaultProfile(configSpec)
- if err != nil {
- return nil, errors.Wrapf(err, "loading default seccomp profile failed")
- }
- }
-
- return seccompConfig, nil
-}
diff --git a/pkg/spec/config_linux_nocgo.go b/pkg/spec/config_linux_nocgo.go
deleted file mode 100644
index 8d720b6d4..000000000
--- a/pkg/spec/config_linux_nocgo.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build linux,!cgo
-
-package createconfig
-
-import (
- spec "github.com/opencontainers/runtime-spec/specs-go"
-)
-
-func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
- return nil, nil
-}
diff --git a/pkg/spec/config_unsupported.go b/pkg/spec/config_unsupported.go
deleted file mode 100644
index 568afde55..000000000
--- a/pkg/spec/config_unsupported.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// +build !linux
-
-package createconfig
-
-import (
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/pkg/errors"
-)
-
-func getSeccompConfig(config *SecurityConfig, configSpec *spec.Spec) (*spec.LinuxSeccomp, error) {
- return nil, errors.New("function not supported on non-linux OS's")
-}
-func addDevice(g *generate.Generator, device string) error {
- return errors.New("function not implemented")
-}
-
-func addPrivilegedDevices(g *generate.Generator) error {
- return errors.New("function not implemented")
-}
-
-func (c *CreateConfig) createBlockIO() (*spec.LinuxBlockIO, error) {
- return nil, errors.New("function not implemented")
-}
-
-func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrottleDevice, error) {
- return nil, errors.New("function not implemented")
-}
-
-func DevicesFromPath(g *generate.Generator, devicePath string) error {
- return errors.New("function not implemented")
-}
-
-func deviceCgroupRules(g *generate.Generator, deviceCgroupRules []string) error {
- return errors.New("function not implemented")
-}
diff --git a/pkg/spec/containerconfig.go b/pkg/spec/containerconfig.go
deleted file mode 100644
index f11d85b7e..000000000
--- a/pkg/spec/containerconfig.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package createconfig
-
-import (
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// MakeContainerConfig generates all configuration necessary to start a
-// container with libpod from a completed CreateConfig struct.
-func (config *CreateConfig) MakeContainerConfig(runtime *libpod.Runtime, pod *libpod.Pod) (*spec.Spec, []libpod.CtrCreateOption, error) {
- if config.Pod != "" && pod == nil {
- return nil, nil, errors.Wrapf(define.ErrInvalidArg, "pod was specified but no pod passed")
- } else if config.Pod == "" && pod != nil {
- return nil, nil, errors.Wrapf(define.ErrInvalidArg, "pod was given but no pod is specified")
- }
-
- // Parse volumes flag into OCI spec mounts and libpod Named Volumes.
- // If there is an identical mount in the OCI spec, we will replace it
- // with a mount generated here.
- mounts, namedVolumes, err := config.parseVolumes(runtime)
- if err != nil {
- return nil, nil, err
- }
-
- runtimeSpec, err := config.createConfigToOCISpec(runtime, mounts)
- if err != nil {
- return nil, nil, err
- }
-
- options, err := config.getContainerCreateOptions(runtime, pod, mounts, namedVolumes)
- if err != nil {
- return nil, nil, err
- }
-
- logrus.Debugf("created OCI spec and options for new container")
-
- return runtimeSpec, options, nil
-}
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
deleted file mode 100644
index 4887e9262..000000000
--- a/pkg/spec/createconfig.go
+++ /dev/null
@@ -1,426 +0,0 @@
-package createconfig
-
-import (
- "context"
- "os"
- "strconv"
- "strings"
- "syscall"
-
- "github.com/containers/image/v5/manifest"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/namespaces"
- "github.com/containers/podman/v2/pkg/seccomp"
- "github.com/containers/storage"
- "github.com/docker/go-connections/nat"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// Type constants
-const (
- bps = iota
- iops
-)
-
-// CreateResourceConfig represents resource elements in CreateConfig
-// structures
-type CreateResourceConfig struct {
- BlkioWeight uint16 // blkio-weight
- BlkioWeightDevice []string // blkio-weight-device
- CgroupConf map[string]string
- CPUPeriod uint64 // cpu-period
- CPUQuota int64 // cpu-quota
- CPURtPeriod uint64 // cpu-rt-period
- CPURtRuntime int64 // cpu-rt-runtime
- CPUShares uint64 // cpu-shares
- CPUs float64 // cpus
- CPUsetCPUs string
- CPUsetMems string // cpuset-mems
- DeviceCgroupRules []string //device-cgroup-rule
- DeviceReadBps []string // device-read-bps
- DeviceReadIOps []string // device-read-iops
- DeviceWriteBps []string // device-write-bps
- DeviceWriteIOps []string // device-write-iops
- DisableOomKiller bool // oom-kill-disable
- KernelMemory int64 // kernel-memory
- Memory int64 //memory
- MemoryReservation int64 // memory-reservation
- MemorySwap int64 //memory-swap
- MemorySwappiness int // memory-swappiness
- OomScoreAdj int //oom-score-adj
- PidsLimit int64 // pids-limit
- ShmSize int64
- Ulimit []string //ulimit
-}
-
-// PidConfig configures the pid namespace for the container
-type PidConfig struct {
- PidMode namespaces.PidMode //pid
-}
-
-// IpcConfig configures the ipc namespace for the container
-type IpcConfig struct {
- IpcMode namespaces.IpcMode //ipc
-}
-
-// CgroupConfig configures the cgroup namespace for the container
-type CgroupConfig struct {
- Cgroups string
- Cgroupns string
- CgroupParent string // cgroup-parent
- CgroupMode namespaces.CgroupMode //cgroup
-}
-
-// UserConfig configures the user namespace for the container
-type UserConfig struct {
- GroupAdd []string // group-add
- IDMappings *storage.IDMappingOptions
- UsernsMode namespaces.UsernsMode //userns
- User string //user
-}
-
-// UtsConfig configures the uts namespace for the container
-type UtsConfig struct {
- UtsMode namespaces.UTSMode //uts
- NoHosts bool
- HostAdd []string //add-host
- Hostname string
-}
-
-// NetworkConfig configures the network namespace for the container
-type NetworkConfig struct {
- DNSOpt []string //dns-opt
- DNSSearch []string //dns-search
- DNSServers []string //dns
- ExposedPorts map[nat.Port]struct{}
- HTTPProxy bool
- IP6Address string //ipv6
- IPAddress string //ip
- LinkLocalIP []string // link-local-ip
- MacAddress string //mac-address
- NetMode namespaces.NetworkMode //net
- Network string //network
- NetworkAlias []string //network-alias
- PortBindings nat.PortMap
- Publish []string //publish
- PublishAll bool //publish-all
-}
-
-// SecurityConfig configures the security features for the container
-type SecurityConfig struct {
- CapAdd []string // cap-add
- CapDrop []string // cap-drop
- CapRequired []string // cap-required
- LabelOpts []string //SecurityOpts
- NoNewPrivs bool //SecurityOpts
- ApparmorProfile string //SecurityOpts
- SeccompProfilePath string //SecurityOpts
- SeccompProfileFromImage string // seccomp profile from the container image
- SeccompPolicy seccomp.Policy
- SecurityOpts []string
- Privileged bool //privileged
- ReadOnlyRootfs bool //read-only
- ReadOnlyTmpfs bool //read-only-tmpfs
- Sysctl map[string]string //sysctl
- ProcOpts []string
-}
-
-// CreateConfig is a pre OCI spec structure. It represents user input from varlink or the CLI
-// swagger:model CreateConfig
-type CreateConfig struct {
- Annotations map[string]string
- Args []string
- CidFile string
- ConmonPidFile string
- Command []string // Full command that will be used
- UserCommand []string // User-entered command (or image CMD)
- Detach bool // detach
- Devices []string // device
- Entrypoint []string //entrypoint
- Env map[string]string //env
- HealthCheck *manifest.Schema2HealthConfig
- Init bool // init
- InitPath string //init-path
- Image string
- ImageID string
- RawImageName string
- BuiltinImgVolumes map[string]struct{} // volumes defined in the image config
- ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore
- Interactive bool //interactive
- Labels map[string]string //label
- LogDriver string // log-driver
- LogDriverOpt []string // log-opt
- Name string //name
- PodmanPath string
- Pod string //pod
- Quiet bool //quiet
- Resources CreateResourceConfig
- RestartPolicy string
- Rm bool //rm
- Rmi bool //rmi
- StopSignal syscall.Signal // stop-signal
- StopTimeout uint // stop-timeout
- Systemd bool
- Tmpfs []string // tmpfs
- Tty bool //tty
- Mounts []spec.Mount
- MountsFlag []string // mounts
- NamedVolumes []*libpod.ContainerNamedVolume
- Volumes []string //volume
- VolumesFrom []string
- WorkDir string //workdir
- Rootfs string
- Security SecurityConfig
- Syslog bool // Whether to enable syslog on exit commands
-
- // Namespaces
- Pid PidConfig
- Ipc IpcConfig
- Cgroup CgroupConfig
- User UserConfig
- Uts UtsConfig
- Network NetworkConfig
-}
-
-func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
-func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
-
-// CreateBlockIO returns a LinuxBlockIO struct from a CreateConfig
-func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) {
- return c.createBlockIO()
-}
-
-func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, error) {
- config, err := runtime.GetConfig()
- if err != nil {
- return nil, err
- }
- storageConfig := runtime.StorageConfig()
-
- // We need a cleanup process for containers in the current model.
- // But we can't assume that the caller is Podman - it could be another
- // user of the API.
- // As such, provide a way to specify a path to Podman, so we can
- // still invoke a cleanup process.
- cmd := c.PodmanPath
- if cmd == "" {
- cmd, _ = os.Executable()
- }
-
- command := []string{cmd,
- "--root", storageConfig.GraphRoot,
- "--runroot", storageConfig.RunRoot,
- "--log-level", logrus.GetLevel().String(),
- "--cgroup-manager", config.Engine.CgroupManager,
- "--tmpdir", config.Engine.TmpDir,
- }
- if config.Engine.OCIRuntime != "" {
- command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...)
- }
- if storageConfig.GraphDriverName != "" {
- command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...)
- }
- for _, opt := range storageConfig.GraphDriverOptions {
- command = append(command, []string{"--storage-opt", opt}...)
- }
- if config.Engine.EventsLogger != "" {
- command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...)
- }
-
- if c.Syslog {
- command = append(command, "--syslog", "true")
- }
- command = append(command, []string{"container", "cleanup"}...)
-
- if c.Rm {
- command = append(command, "--rm")
- }
-
- if c.Rmi {
- command = append(command, "--rmi")
- }
-
- return command, nil
-}
-
-// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
-func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod, mounts []spec.Mount, namedVolumes []*libpod.ContainerNamedVolume) ([]libpod.CtrCreateOption, error) {
- var options []libpod.CtrCreateOption
- var err error
-
- if c.Interactive {
- options = append(options, libpod.WithStdin())
- }
- if c.Systemd {
- options = append(options, libpod.WithSystemd())
- }
- if c.Name != "" {
- logrus.Debugf("setting container name %s", c.Name)
- options = append(options, libpod.WithName(c.Name))
- }
- if c.Pod != "" {
- logrus.Debugf("adding container to pod %s", c.Pod)
- options = append(options, runtime.WithPod(pod))
- }
-
- // handle some spec from the InfraContainer when it's a pod
- if pod != nil && pod.HasInfraContainer() {
- InfraCtr, err := pod.InfraContainer()
- if err != nil {
- return nil, err
- }
- // handle the pod.spec.hostAliases
- options = append(options, libpod.WithHosts(InfraCtr.HostsAdd()))
- }
-
- if len(mounts) != 0 || len(namedVolumes) != 0 {
- destinations := []string{}
-
- // Take all mount and named volume destinations.
- for _, mount := range mounts {
- destinations = append(destinations, mount.Destination)
- }
- for _, volume := range namedVolumes {
- destinations = append(destinations, volume.Dest)
- }
-
- options = append(options, libpod.WithUserVolumes(destinations))
- }
-
- if len(namedVolumes) != 0 {
- options = append(options, libpod.WithNamedVolumes(namedVolumes))
- }
-
- if len(c.UserCommand) != 0 {
- options = append(options, libpod.WithCommand(c.UserCommand))
- }
-
- // Add entrypoint if it was set
- // If it's empty it's because it was explicitly set to ""
- if c.Entrypoint != nil {
- options = append(options, libpod.WithEntrypoint(c.Entrypoint))
- }
-
- // TODO: MNT, USER, CGROUP
- options = append(options, libpod.WithStopSignal(c.StopSignal))
- options = append(options, libpod.WithStopTimeout(c.StopTimeout))
-
- logPath, logTag := getLoggingOpts(c.LogDriverOpt)
- if logPath != "" {
- options = append(options, libpod.WithLogPath(logPath))
- }
- if logTag != "" {
- options = append(options, libpod.WithLogTag(logTag))
- }
-
- if c.LogDriver != "" {
- options = append(options, libpod.WithLogDriver(c.LogDriver))
- }
-
- secOpts, err := c.Security.ToCreateOptions()
- if err != nil {
- return nil, err
- }
- options = append(options, secOpts...)
-
- nsOpts, err := c.Cgroup.ToCreateOptions(runtime)
- if err != nil {
- return nil, err
- }
- options = append(options, nsOpts...)
-
- nsOpts, err = c.Ipc.ToCreateOptions(runtime)
- if err != nil {
- return nil, err
- }
- options = append(options, nsOpts...)
-
- nsOpts, err = c.Pid.ToCreateOptions(runtime)
- if err != nil {
- return nil, err
- }
- options = append(options, nsOpts...)
-
- nsOpts, err = c.Network.ToCreateOptions(runtime, &c.User)
- if err != nil {
- return nil, err
- }
- options = append(options, nsOpts...)
-
- nsOpts, err = c.Uts.ToCreateOptions(runtime, pod)
- if err != nil {
- return nil, err
- }
- options = append(options, nsOpts...)
-
- nsOpts, err = c.User.ToCreateOptions(runtime)
- if err != nil {
- return nil, err
- }
- options = append(options, nsOpts...)
-
- // Gather up the options for NewContainer which consist of With... funcs
- options = append(options, libpod.WithRootFSFromImage(c.ImageID, c.Image, c.RawImageName))
- options = append(options, libpod.WithConmonPidFile(c.ConmonPidFile))
- options = append(options, libpod.WithLabels(c.Labels))
- options = append(options, libpod.WithShmSize(c.Resources.ShmSize))
- if c.Rootfs != "" {
- options = append(options, libpod.WithRootFS(c.Rootfs))
- }
- // Default used if not overridden on command line
-
- if c.RestartPolicy != "" {
- if c.RestartPolicy == "unless-stopped" {
- return nil, errors.Wrapf(define.ErrInvalidArg, "the unless-stopped restart policy is not supported")
- }
-
- split := strings.Split(c.RestartPolicy, ":")
- if len(split) > 1 {
- numTries, err := strconv.Atoi(split[1])
- if err != nil {
- return nil, errors.Wrapf(err, "%s is not a valid number of retries for restart policy", split[1])
- }
- if numTries < 0 {
- return nil, errors.Wrapf(define.ErrInvalidArg, "restart policy requires a positive number of retries")
- }
- options = append(options, libpod.WithRestartRetries(uint(numTries)))
- }
- options = append(options, libpod.WithRestartPolicy(split[0]))
- }
-
- // Always use a cleanup process to clean up Podman after termination
- exitCmd, err := c.createExitCommand(runtime)
- if err != nil {
- return nil, err
- }
- options = append(options, libpod.WithExitCommand(exitCmd))
-
- if c.HealthCheck != nil {
- options = append(options, libpod.WithHealthCheck(c.HealthCheck))
- logrus.Debugf("New container has a health check")
- }
- return options, nil
-}
-
-// AddPrivilegedDevices iterates through host devices and adds all
-// host devices to the spec
-func AddPrivilegedDevices(g *generate.Generator) error {
- return addPrivilegedDevices(g)
-}
-
-func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, createConfig *CreateConfig, pod *libpod.Pod) (*libpod.Container, error) {
- runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod)
- if err != nil {
- return nil, err
- }
-
- ctr, err := r.NewContainer(ctx, runtimeSpec, options...)
- if err != nil {
- return nil, err
- }
- return ctr, nil
-}
diff --git a/pkg/spec/namespaces.go b/pkg/spec/namespaces.go
deleted file mode 100644
index 8f98a9786..000000000
--- a/pkg/spec/namespaces.go
+++ /dev/null
@@ -1,463 +0,0 @@
-package createconfig
-
-import (
- "net"
- "os"
- "strconv"
- "strings"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/cgroups"
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/go-connections/nat"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// DefaultKernelNamespaces is a comma-separated list of default kernel
-// namespaces.
-const DefaultKernelNamespaces = "cgroup,ipc,net,uts"
-
-// ToCreateOptions converts the input to a slice of container create options.
-func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserConfig) ([]libpod.CtrCreateOption, error) {
- var portBindings []ocicni.PortMapping
- var err error
- if len(c.PortBindings) > 0 {
- portBindings, err = NatToOCIPortBindings(c.PortBindings)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to create port bindings")
- }
- }
-
- options := make([]libpod.CtrCreateOption, 0)
- userNetworks := c.NetMode.UserDefined()
- networks := make([]string, 0)
-
- if IsPod(userNetworks) {
- userNetworks = ""
- }
- if userNetworks != "" {
- for _, netName := range strings.Split(userNetworks, ",") {
- if netName == "" {
- return nil, errors.Errorf("container networks %q invalid", userNetworks)
- }
- networks = append(networks, netName)
- }
- }
-
- switch {
- case c.NetMode.IsNS():
- ns := c.NetMode.NS()
- if ns == "" {
- return nil, errors.Errorf("invalid empty user-defined network namespace")
- }
- _, err := os.Stat(ns)
- if err != nil {
- return nil, err
- }
- case c.NetMode.IsContainer():
- connectedCtr, err := runtime.LookupContainer(c.NetMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container())
- }
- options = append(options, libpod.WithNetNSFrom(connectedCtr))
- case !c.NetMode.IsHost() && !c.NetMode.IsNone():
- postConfigureNetNS := userns.getPostConfigureNetNS()
- options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks))
- }
-
- if len(c.DNSSearch) > 0 {
- options = append(options, libpod.WithDNSSearch(c.DNSSearch))
- }
- if len(c.DNSServers) > 0 {
- if len(c.DNSServers) == 1 && strings.ToLower(c.DNSServers[0]) == "none" {
- options = append(options, libpod.WithUseImageResolvConf())
- } else {
- options = append(options, libpod.WithDNS(c.DNSServers))
- }
- }
- if len(c.DNSOpt) > 0 {
- options = append(options, libpod.WithDNSOption(c.DNSOpt))
- }
- if c.IPAddress != "" {
- ip := net.ParseIP(c.IPAddress)
- if ip == nil {
- return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress)
- } else if ip.To4() == nil {
- return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress)
- }
- options = append(options, libpod.WithStaticIP(ip))
- }
-
- if c.MacAddress != "" {
- mac, err := net.ParseMAC(c.MacAddress)
- if err != nil {
- return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err)
- }
- options = append(options, libpod.WithStaticMAC(mac))
- }
-
- return options, nil
-}
-
-// ConfigureGenerator configures the generator based according to the current
-// state of the NetworkConfig.
-func (c *NetworkConfig) ConfigureGenerator(g *generate.Generator) error {
- netMode := c.NetMode
- netCtr := netMode.Container()
- switch {
- case netMode.IsHost():
- logrus.Debug("Using host netmode")
- if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
- return err
- }
- case netMode.IsNone():
- logrus.Debug("Using none netmode")
- case netMode.IsBridge():
- logrus.Debug("Using bridge netmode")
- case netCtr != "":
- logrus.Debugf("using container %s netmode", netCtr)
- case IsNS(string(netMode)):
- logrus.Debug("Using ns netmode")
- if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode))); err != nil {
- return err
- }
- case IsPod(string(netMode)):
- logrus.Debug("Using pod netmode, unless pod is not sharing")
- case netMode.IsSlirp4netns():
- logrus.Debug("Using slirp4netns netmode")
- case netMode.IsUserDefined():
- logrus.Debug("Using user defined netmode")
- default:
- return errors.Errorf("unknown network mode")
- }
-
- if c.HTTPProxy {
- for _, envSpec := range []string{
- "http_proxy",
- "HTTP_PROXY",
- "https_proxy",
- "HTTPS_PROXY",
- "ftp_proxy",
- "FTP_PROXY",
- "no_proxy",
- "NO_PROXY",
- } {
- envVal := os.Getenv(envSpec)
- if envVal != "" {
- g.AddProcessEnv(envSpec, envVal)
- }
- }
- }
-
- if g.Config.Annotations == nil {
- g.Config.Annotations = make(map[string]string)
- }
-
- if c.PublishAll {
- g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
- } else {
- g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
- }
-
- return nil
-}
-
-// NatToOCIPortBindings iterates a nat.portmap slice and creates []ocicni portmapping slice
-func NatToOCIPortBindings(ports nat.PortMap) ([]ocicni.PortMapping, error) {
- var portBindings []ocicni.PortMapping
- for containerPb, hostPb := range ports {
- var pm ocicni.PortMapping
- pm.ContainerPort = int32(containerPb.Int())
- for _, i := range hostPb {
- var hostPort int
- var err error
- pm.HostIP = i.HostIP
- if i.HostPort == "" {
- hostPort = containerPb.Int()
- } else {
- hostPort, err = strconv.Atoi(i.HostPort)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to convert host port to integer")
- }
- }
-
- pm.HostPort = int32(hostPort)
- pm.Protocol = containerPb.Proto()
- portBindings = append(portBindings, pm)
- }
- }
- return portBindings, nil
-}
-
-// ToCreateOptions converts the input to container create options.
-func (c *CgroupConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- if c.CgroupMode.IsNS() {
- ns := c.CgroupMode.NS()
- if ns == "" {
- return nil, errors.Errorf("invalid empty user-defined network namespace")
- }
- _, err := os.Stat(ns)
- if err != nil {
- return nil, err
- }
- } else if c.CgroupMode.IsContainer() {
- connectedCtr, err := runtime.LookupContainer(c.CgroupMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", c.CgroupMode.Container())
- }
- options = append(options, libpod.WithCgroupNSFrom(connectedCtr))
- }
-
- if c.CgroupParent != "" {
- options = append(options, libpod.WithCgroupParent(c.CgroupParent))
- }
-
- if c.Cgroups != "" {
- options = append(options, libpod.WithCgroupsMode(c.Cgroups))
- }
-
- return options, nil
-}
-
-// ToCreateOptions converts the input to container create options.
-func (c *UserConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- switch {
- case c.UsernsMode.IsNS():
- ns := c.UsernsMode.NS()
- if ns == "" {
- return nil, errors.Errorf("invalid empty user-defined user namespace")
- }
- _, err := os.Stat(ns)
- if err != nil {
- return nil, err
- }
- options = append(options, libpod.WithIDMappings(*c.IDMappings))
- case c.UsernsMode.IsContainer():
- connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container())
- }
- options = append(options, libpod.WithUserNSFrom(connectedCtr))
- default:
- options = append(options, libpod.WithIDMappings(*c.IDMappings))
- }
-
- options = append(options, libpod.WithUser(c.User))
- options = append(options, libpod.WithGroups(c.GroupAdd))
-
- return options, nil
-}
-
-// ConfigureGenerator configures the generator according to the current state
-// of the UserConfig.
-func (c *UserConfig) ConfigureGenerator(g *generate.Generator) error {
- if IsNS(string(c.UsernsMode)) {
- if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), NS(string(c.UsernsMode))); err != nil {
- return err
- }
- // runc complains if no mapping is specified, even if we join another ns. So provide a dummy mapping
- g.AddLinuxUIDMapping(uint32(0), uint32(0), uint32(1))
- g.AddLinuxGIDMapping(uint32(0), uint32(0), uint32(1))
- }
-
- if (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost() {
- if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
- return err
- }
- }
- for _, uidmap := range c.IDMappings.UIDMap {
- g.AddLinuxUIDMapping(uint32(uidmap.HostID), uint32(uidmap.ContainerID), uint32(uidmap.Size))
- }
- for _, gidmap := range c.IDMappings.GIDMap {
- g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
- }
- return nil
-}
-
-func (c *UserConfig) getPostConfigureNetNS() bool {
- hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || c.UsernsMode.IsAuto() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
- postConfigureNetNS := hasUserns && !c.UsernsMode.IsHost()
- return postConfigureNetNS
-}
-
-// InNS returns true if the UserConfig indicates to be in a dedicated user
-// namespace.
-func (c *UserConfig) InNS(isRootless bool) bool {
- hasUserns := c.UsernsMode.IsContainer() || c.UsernsMode.IsNS() || c.UsernsMode.IsAuto() || len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0
- return isRootless || (hasUserns && !c.UsernsMode.IsHost())
-}
-
-// ToCreateOptions converts the input to container create options.
-func (c *IpcConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- if c.IpcMode.IsHost() {
- options = append(options, libpod.WithShmDir("/dev/shm"))
- } else if c.IpcMode.IsContainer() {
- connectedCtr, err := runtime.LookupContainer(c.IpcMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", c.IpcMode.Container())
- }
-
- options = append(options, libpod.WithIPCNSFrom(connectedCtr))
- options = append(options, libpod.WithShmDir(connectedCtr.ShmDir()))
- }
-
- return options, nil
-}
-
-// ConfigureGenerator configures the generator according to the current state
-// of the IpcConfig.
-func (c *IpcConfig) ConfigureGenerator(g *generate.Generator) error {
- ipcMode := c.IpcMode
- if IsNS(string(ipcMode)) {
- return g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), NS(string(ipcMode)))
- }
- if ipcMode.IsHost() {
- return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
- }
- if ipcCtr := ipcMode.Container(); ipcCtr != "" {
- logrus.Debugf("Using container %s ipcmode", ipcCtr)
- }
-
- return nil
-}
-
-// ConfigureGenerator configures the generator according to the current state
-// of the CgroupConfig.
-func (c *CgroupConfig) ConfigureGenerator(g *generate.Generator) error {
- cgroupMode := c.CgroupMode
- if cgroupMode.IsDefaultValue() {
- // If the value is not specified, default to "private" on cgroups v2 and "host" on cgroups v1.
- unified, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return err
- }
- if unified {
- cgroupMode = "private"
- } else {
- cgroupMode = "host"
- }
- }
- if cgroupMode.IsNS() {
- return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), NS(string(cgroupMode)))
- }
- if cgroupMode.IsHost() {
- return g.RemoveLinuxNamespace(string(spec.CgroupNamespace))
- }
- if cgroupMode.IsPrivate() {
- return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
- }
- if cgCtr := cgroupMode.Container(); cgCtr != "" {
- logrus.Debugf("Using container %s cgroup mode", cgCtr)
- }
- return nil
-}
-
-// ToCreateOptions converts the input to container create options.
-func (c *PidConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- if c.PidMode.IsContainer() {
- connectedCtr, err := runtime.LookupContainer(c.PidMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", c.PidMode.Container())
- }
-
- options = append(options, libpod.WithPIDNSFrom(connectedCtr))
- }
-
- return options, nil
-}
-
-// ConfigureGenerator configures the generator according to the current state
-// of the PidConfig.
-func (c *PidConfig) ConfigureGenerator(g *generate.Generator) error {
- pidMode := c.PidMode
- if IsNS(string(pidMode)) {
- return g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), NS(string(pidMode)))
- }
- if pidMode.IsHost() {
- return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
- }
- if pidCtr := pidMode.Container(); pidCtr != "" {
- logrus.Debugf("using container %s pidmode", pidCtr)
- }
- if IsPod(string(pidMode)) {
- logrus.Debug("using pod pidmode")
- }
- return nil
-}
-
-// ToCreateOptions converts the input to container create options.
-func (c *UtsConfig) ToCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod) ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- if IsPod(string(c.UtsMode)) {
- options = append(options, libpod.WithUTSNSFromPod(pod))
- }
- if c.UtsMode.IsContainer() {
- connectedCtr, err := runtime.LookupContainer(c.UtsMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container())
- }
-
- options = append(options, libpod.WithUTSNSFrom(connectedCtr))
- }
- if c.NoHosts {
- options = append(options, libpod.WithUseImageHosts())
- }
- if len(c.HostAdd) > 0 && !c.NoHosts {
- options = append(options, libpod.WithHosts(c.HostAdd))
- }
-
- return options, nil
-}
-
-// ConfigureGenerator configures the generator according to the current state
-// of the UtsConfig.
-func (c *UtsConfig) ConfigureGenerator(g *generate.Generator, net *NetworkConfig, runtime *libpod.Runtime) error {
- hostname := c.Hostname
- utsCtrID := c.UtsMode.Container()
- var err error
- if hostname == "" {
- switch {
- case utsCtrID != "":
- utsCtr, err := runtime.LookupContainer(utsCtrID)
- if err != nil {
- return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
- }
- hostname = utsCtr.Hostname()
- case net.NetMode.IsHost() || c.UtsMode.IsHost():
- hostname, err = os.Hostname()
- if err != nil {
- return errors.Wrap(err, "unable to retrieve hostname of the host")
- }
- default:
- logrus.Debug("No hostname set; container's hostname will default to runtime default")
- }
- }
- g.RemoveHostname()
- if c.Hostname != "" || !c.UtsMode.IsHost() {
- // Set the hostname in the OCI configuration only
- // if specified by the user or if we are creating
- // a new UTS namespace.
- g.SetHostname(hostname)
- }
- g.AddProcessEnv("HOSTNAME", hostname)
-
- utsMode := c.UtsMode
- if IsNS(string(utsMode)) {
- return g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), NS(string(utsMode)))
- }
- if utsMode.IsHost() {
- return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
- }
- if utsCtr := utsMode.Container(); utsCtr != "" {
- logrus.Debugf("using container %s utsmode", utsCtr)
- }
- return nil
-}
diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go
deleted file mode 100644
index 9ebcf8d29..000000000
--- a/pkg/spec/parse.go
+++ /dev/null
@@ -1,225 +0,0 @@
-package createconfig
-
-import (
- "fmt"
- "regexp"
- "strconv"
- "strings"
-
- "github.com/docker/go-units"
- "github.com/pkg/errors"
-)
-
-// deviceCgroupRulegex defines the valid format of device-cgroup-rule
-var deviceCgroupRuleRegex = regexp.MustCompile(`^([acb]) ([0-9]+|\*):([0-9]+|\*) ([rwm]{1,3})$`)
-
-// Pod signifies a kernel namespace is being shared
-// by a container with the pod it is associated with
-const Pod = "pod"
-
-// weightDevice is a structure that holds device:weight pair
-type weightDevice struct {
- Path string
- Weight uint16
-}
-
-func (w *weightDevice) String() string {
- return fmt.Sprintf("%s:%d", w.Path, w.Weight)
-}
-
-// LinuxNS is a struct that contains namespace information
-// It implemented Valid to show it is a valid namespace
-type LinuxNS interface {
- Valid() bool
-}
-
-// IsNS returns if the specified string has a ns: prefix
-func IsNS(s string) bool {
- parts := strings.SplitN(s, ":", 2)
- return len(parts) > 1 && parts[0] == "ns"
-}
-
-// IsPod returns if the specified string is pod
-func IsPod(s string) bool {
- return s == Pod
-}
-
-// Valid checks the validity of a linux namespace
-// s should be the string representation of ns
-func Valid(s string, ns LinuxNS) bool {
- return IsPod(s) || IsNS(s) || ns.Valid()
-}
-
-// NS is the path to the namespace to join.
-func NS(s string) string {
- parts := strings.SplitN(s, ":", 2)
- if len(parts) > 1 {
- return parts[1]
- }
- return ""
-}
-
-// ValidateweightDevice validates that the specified string has a valid device-weight format
-// for blkio-weight-device flag
-func ValidateweightDevice(val string) (*weightDevice, error) {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- weight, err := strconv.ParseUint(split[1], 10, 0)
- if err != nil {
- return nil, fmt.Errorf("invalid weight for device: %s", val)
- }
- if weight > 0 && (weight < 10 || weight > 1000) {
- return nil, fmt.Errorf("invalid weight for device: %s", val)
- }
-
- return &weightDevice{
- Path: split[0],
- Weight: uint16(weight),
- }, nil
-}
-
-// throttleDevice is a structure that holds device:rate_per_second pair
-type throttleDevice struct {
- path string
- rate uint64
-}
-
-func (t *throttleDevice) String() string {
- return fmt.Sprintf("%s:%d", t.path, t.rate)
-}
-
-// validateBpsDevice validates that the specified string has a valid device-rate format
-// for device-read-bps and device-write-bps flags
-func validateBpsDevice(val string) (*throttleDevice, error) {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- rate, err := units.RAMInBytes(split[1])
- if err != nil {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
- }
- if rate < 0 {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
- }
-
- return &throttleDevice{
- path: split[0],
- rate: uint64(rate),
- }, nil
-}
-
-// validateIOpsDevice validates that the specified string has a valid device-rate format
-// for device-write-iops and device-read-iops flags
-func validateIOpsDevice(val string) (*throttleDevice, error) { //nolint
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- rate, err := strconv.ParseUint(split[1], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
- }
- return &throttleDevice{
- path: split[0],
- rate: rate,
- }, nil
-}
-
-// getLoggingOpts splits the path= and tag= options provided to --log-opt.
-func getLoggingOpts(opts []string) (string, string) {
- var path, tag string
- for _, opt := range opts {
- arr := strings.SplitN(opt, "=", 2)
- if len(arr) == 2 {
- if strings.TrimSpace(arr[0]) == "path" {
- path = strings.TrimSpace(arr[1])
- } else if strings.TrimSpace(arr[0]) == "tag" {
- tag = strings.TrimSpace(arr[1])
- }
- }
- if path != "" && tag != "" {
- break
- }
- }
- return path, tag
-}
-
-// ParseDevice parses device mapping string to a src, dest & permissions string
-func ParseDevice(device string) (string, string, string, error) { //nolint
- src := ""
- dst := ""
- permissions := "rwm"
- arr := strings.Split(device, ":")
- switch len(arr) {
- case 3:
- if !IsValidDeviceMode(arr[2]) {
- return "", "", "", fmt.Errorf("invalid device mode: %s", arr[2])
- }
- permissions = arr[2]
- fallthrough
- case 2:
- if IsValidDeviceMode(arr[1]) {
- permissions = arr[1]
- } else {
- if len(arr[1]) == 0 || arr[1][0] != '/' {
- return "", "", "", fmt.Errorf("invalid device mode: %s", arr[1])
- }
- dst = arr[1]
- }
- fallthrough
- case 1:
- src = arr[0]
- default:
- return "", "", "", fmt.Errorf("invalid device specification: %s", device)
- }
-
- if dst == "" {
- dst = src
- }
- return src, dst, permissions, nil
-}
-
-// IsValidDeviceMode checks if the mode for device is valid or not.
-// IsValid mode is a composition of r (read), w (write), and m (mknod).
-func IsValidDeviceMode(mode string) bool {
- var legalDeviceMode = map[rune]bool{
- 'r': true,
- 'w': true,
- 'm': true,
- }
- if mode == "" {
- return false
- }
- for _, c := range mode {
- if !legalDeviceMode[c] {
- return false
- }
- legalDeviceMode[c] = false
- }
- return true
-}
-
-// validateDeviceCgroupRule validates the format of deviceCgroupRule
-func validateDeviceCgroupRule(deviceCgroupRule string) error {
- if !deviceCgroupRuleRegex.MatchString(deviceCgroupRule) {
- return errors.Errorf("invalid device cgroup rule format: '%s'", deviceCgroupRule)
- }
- return nil
-}
-
-// parseDeviceCgroupRule matches and parses the deviceCgroupRule into slice
-func parseDeviceCgroupRule(deviceCgroupRule string) [][]string {
- return deviceCgroupRuleRegex.FindAllStringSubmatch(deviceCgroupRule, -1)
-}
diff --git a/pkg/spec/ports.go b/pkg/spec/ports.go
deleted file mode 100644
index bdd26bd83..000000000
--- a/pkg/spec/ports.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package createconfig
-
-import (
- "fmt"
- "net"
- "strconv"
-
- "github.com/docker/go-connections/nat"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// ExposedPorts parses user and image ports and returns binding information
-func ExposedPorts(expose, publish []string, publishAll bool, imageExposedPorts map[string]struct{}) (map[nat.Port][]nat.PortBinding, error) {
- containerPorts := make(map[string]string)
-
- // add expose ports from the image itself
- for expose := range imageExposedPorts {
- _, port := nat.SplitProtoPort(expose)
- containerPorts[port] = ""
- }
-
- // add the expose ports from the user (--expose)
- // can be single or a range
- for _, expose := range expose {
- //support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
- _, port := nat.SplitProtoPort(expose)
- //parse the start and end port and create a sequence of ports to expose
- //if expose a port, the start and end port are the same
- start, end, err := nat.ParsePortRange(port)
- if err != nil {
- return nil, fmt.Errorf("invalid range format for --expose: %s, error: %s", expose, err)
- }
- for i := start; i <= end; i++ {
- containerPorts[strconv.Itoa(int(i))] = ""
- }
- }
-
- // parse user inputted port bindings
- pbPorts, portBindings, err := nat.ParsePortSpecs(publish)
- if err != nil {
- return nil, err
- }
-
- // delete exposed container ports if being used by -p
- for i := range pbPorts {
- delete(containerPorts, i.Port())
- }
-
- // iterate container ports and make port bindings from them
- if publishAll {
- for e := range containerPorts {
- //support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
- //proto, port := nat.SplitProtoPort(e)
- p, err := nat.NewPort("tcp", e)
- if err != nil {
- return nil, err
- }
- rp, err := getRandomPort()
- if err != nil {
- return nil, err
- }
- logrus.Debug(fmt.Sprintf("Using random host port %d with container port %d", rp, p.Int()))
- portBindings[p] = CreatePortBinding(rp, "")
- }
- }
-
- // We need to see if any host ports are not populated and if so, we need to assign a
- // random port to them.
- for k, pb := range portBindings {
- if pb[0].HostPort == "" {
- hostPort, err := getRandomPort()
- if err != nil {
- return nil, err
- }
- logrus.Debug(fmt.Sprintf("Using random host port %d with container port %s", hostPort, k.Port()))
- pb[0].HostPort = strconv.Itoa(hostPort)
- }
- }
- return portBindings, nil
-}
-
-func getRandomPort() (int, error) {
- l, err := net.Listen("tcp", ":0")
- if err != nil {
- return 0, errors.Wrapf(err, "unable to get free port")
- }
- defer l.Close()
- _, randomPort, err := net.SplitHostPort(l.Addr().String())
- if err != nil {
- return 0, errors.Wrapf(err, "unable to determine free port")
- }
- rp, err := strconv.Atoi(randomPort)
- if err != nil {
- return 0, errors.Wrapf(err, "unable to convert random port to int")
- }
- return rp, nil
-}
-
-//CreatePortBinding takes port (int) and IP (string) and creates an array of portbinding structs
-func CreatePortBinding(hostPort int, hostIP string) []nat.PortBinding {
- pb := nat.PortBinding{
- HostPort: strconv.Itoa(hostPort),
- }
- pb.HostIP = hostIP
- return []nat.PortBinding{pb}
-}
diff --git a/pkg/spec/security.go b/pkg/spec/security.go
deleted file mode 100644
index 5f7db7edb..000000000
--- a/pkg/spec/security.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package createconfig
-
-import (
- "fmt"
- "strings"
-
- "github.com/containers/common/pkg/capabilities"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/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
-// options.
-func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- options = append(options, libpod.WithSecLabels(c.LabelOpts))
- options = append(options, libpod.WithPrivileged(c.Privileged))
- return options, nil
-}
-
-// SetLabelOpts sets the label options of the SecurityConfig according to the
-// input.
-func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error {
- if c.Privileged {
- c.LabelOpts = label.DisableSecOpt()
- return nil
- }
-
- var labelOpts []string
- if pidConfig.PidMode.IsHost() {
- labelOpts = append(labelOpts, label.DisableSecOpt()...)
- } else if pidConfig.PidMode.IsContainer() {
- ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container())
- }
- secopts, err := label.DupSecOpt(ctr.ProcessLabel())
- if err != nil {
- return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
- }
- labelOpts = append(labelOpts, secopts...)
- }
-
- if ipcConfig.IpcMode.IsHost() {
- labelOpts = append(labelOpts, label.DisableSecOpt()...)
- } else if ipcConfig.IpcMode.IsContainer() {
- ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container())
- }
- secopts, err := label.DupSecOpt(ctr.ProcessLabel())
- if err != nil {
- return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel())
- }
- labelOpts = append(labelOpts, secopts...)
- }
-
- c.LabelOpts = append(c.LabelOpts, labelOpts...)
- return nil
-}
-
-// SetSecurityOpts the the security options (labels, apparmor, seccomp, etc.).
-func (c *SecurityConfig) SetSecurityOpts(runtime *libpod.Runtime, securityOpts []string) error {
- for _, opt := range securityOpts {
- if opt == "no-new-privileges" {
- c.NoNewPrivs = true
- } else {
- con := strings.SplitN(opt, "=", 2)
- if len(con) != 2 {
- return fmt.Errorf("invalid --security-opt 1: %q", opt)
- }
-
- switch con[0] {
- case "proc-opts":
- c.ProcOpts = strings.Split(con[1], ",")
- case "label":
- c.LabelOpts = append(c.LabelOpts, con[1])
- case "apparmor":
- c.ApparmorProfile = con[1]
- case "seccomp":
- c.SeccompProfilePath = con[1]
- default:
- return fmt.Errorf("invalid --security-opt 2: %q", opt)
- }
- }
- }
-
- if c.SeccompProfilePath == "" {
- var err error
- c.SeccompProfilePath, err = libpod.DefaultSeccompPath()
- if err != nil {
- return err
- }
- }
- c.SecurityOpts = securityOpts
- return nil
-}
-
-// ConfigureGenerator configures the generator according to the input.
-func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error {
- // HANDLE CAPABILITIES
- // NOTE: Must happen before SECCOMP
- if c.Privileged {
- g.SetupPrivileged(true)
- }
-
- useNotRoot := func(user string) bool {
- if user == "" || user == "root" || user == "0" {
- return false
- }
- return true
- }
-
- configSpec := g.Config
- var err error
- var defaultCaplist []string
- bounding := configSpec.Process.Capabilities.Bounding
- if useNotRoot(user.User) {
- configSpec.Process.Capabilities.Bounding = defaultCaplist
- }
- defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop)
- if err != nil {
- return err
- }
-
- 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) {
- defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop)
- if err != nil {
- return err
- }
- }
- configSpec.Process.Capabilities.Bounding = defaultCaplist
-
- // HANDLE SECCOMP
- if c.SeccompProfilePath != "unconfined" {
- seccompConfig, err := getSeccompConfig(c, configSpec)
- if err != nil {
- return err
- }
- configSpec.Linux.Seccomp = seccompConfig
- }
-
- // Clear default Seccomp profile from Generator for privileged containers
- if c.SeccompProfilePath == "unconfined" || c.Privileged {
- configSpec.Linux.Seccomp = nil
- }
-
- for _, opt := range c.SecurityOpts {
- // Split on both : and =
- splitOpt := strings.SplitN(opt, "=", 2)
- if len(splitOpt) == 1 {
- splitOpt = strings.Split(opt, ":")
- }
- if len(splitOpt) < 2 {
- continue
- }
- switch splitOpt[0] {
- case "label":
- configSpec.Annotations[define.InspectAnnotationLabel] = splitOpt[1]
- case "seccomp":
- configSpec.Annotations[define.InspectAnnotationSeccomp] = splitOpt[1]
- case "apparmor":
- configSpec.Annotations[define.InspectAnnotationApparmor] = splitOpt[1]
- }
- }
-
- g.SetRootReadonly(c.ReadOnlyRootfs)
- for sysctlKey, sysctlVal := range c.Sysctl {
- g.AddLinuxSysctl(sysctlKey, sysctlVal)
- }
-
- return nil
-}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
deleted file mode 100644
index 81620997f..000000000
--- a/pkg/spec/spec.go
+++ /dev/null
@@ -1,593 +0,0 @@
-package createconfig
-
-import (
- "strings"
-
- "github.com/containers/common/pkg/capabilities"
- cconfig "github.com/containers/common/pkg/config"
- "github.com/containers/common/pkg/sysinfo"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/cgroups"
- "github.com/containers/podman/v2/pkg/env"
- "github.com/containers/podman/v2/pkg/rootless"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/docker/go-units"
- "github.com/opencontainers/runc/libcontainer/user"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
-)
-
-const CpuPeriod = 100000
-
-func GetAvailableGids() (int64, error) {
- idMap, err := user.ParseIDMapFile("/proc/self/gid_map")
- if err != nil {
- return 0, err
- }
- count := int64(0)
- for _, r := range idMap {
- count += r.Count
- }
- return count, nil
-}
-
-// CreateConfigToOCISpec parses information needed to create a container into an OCI runtime spec
-func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userMounts []spec.Mount) (*spec.Spec, error) {
- cgroupPerm := "ro"
- g, err := generate.New("linux")
- if err != nil {
- return nil, err
- }
- // Remove the default /dev/shm mount to ensure we overwrite it
- g.RemoveMount("/dev/shm")
- g.HostSpecific = true
- addCgroup := true
- canMountSys := true
-
- isRootless := rootless.IsRootless()
- inUserNS := config.User.InNS(isRootless)
-
- if inUserNS && config.Network.NetMode.IsHost() {
- canMountSys = false
- }
-
- if config.Security.Privileged && canMountSys {
- cgroupPerm = "rw"
- g.RemoveMount("/sys")
- sysMnt := spec.Mount{
- Destination: "/sys",
- Type: "sysfs",
- Source: "sysfs",
- Options: []string{"rprivate", "nosuid", "noexec", "nodev", "rw"},
- }
- g.AddMount(sysMnt)
- } else if !canMountSys {
- addCgroup = false
- g.RemoveMount("/sys")
- r := "ro"
- if config.Security.Privileged {
- r = "rw"
- }
- sysMnt := spec.Mount{
- Destination: "/sys",
- Type: TypeBind,
- Source: "/sys",
- Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
- }
- g.AddMount(sysMnt)
- if !config.Security.Privileged && isRootless {
- g.AddLinuxMaskedPaths("/sys/kernel")
- }
- }
- var runtimeConfig *cconfig.Config
-
- if runtime != nil {
- runtimeConfig, err = runtime.GetConfig()
- if err != nil {
- return nil, err
- }
- g.Config.Process.Capabilities.Bounding = runtimeConfig.Containers.DefaultCapabilities
- sysctls, err := util.ValidateSysctls(runtimeConfig.Containers.DefaultSysctls)
- if err != nil {
- return nil, err
- }
-
- for name, val := range config.Security.Sysctl {
- sysctls[name] = val
- }
- config.Security.Sysctl = sysctls
- if !util.StringInSlice("host", config.Resources.Ulimit) {
- config.Resources.Ulimit = append(runtimeConfig.Containers.DefaultUlimits, config.Resources.Ulimit...)
- }
- if config.Resources.PidsLimit < 0 && !config.cgroupDisabled() {
- config.Resources.PidsLimit = runtimeConfig.Containers.PidsLimit
- }
-
- } else {
- g.Config.Process.Capabilities.Bounding = cconfig.DefaultCapabilities
- if config.Resources.PidsLimit < 0 && !config.cgroupDisabled() {
- config.Resources.PidsLimit = cconfig.DefaultPidsLimit
- }
- }
-
- gid5Available := true
- if isRootless {
- nGids, err := GetAvailableGids()
- if err != nil {
- return nil, err
- }
- gid5Available = nGids >= 5
- }
- // When using a different user namespace, check that the GID 5 is mapped inside
- // the container.
- if gid5Available && len(config.User.IDMappings.GIDMap) > 0 {
- mappingFound := false
- for _, r := range config.User.IDMappings.GIDMap {
- if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
- mappingFound = true
- break
- }
- }
- if !mappingFound {
- gid5Available = false
- }
-
- }
- if !gid5Available {
- // If we have no GID mappings, the gid=5 default option would fail, so drop it.
- g.RemoveMount("/dev/pts")
- devPts := spec.Mount{
- Destination: "/dev/pts",
- Type: "devpts",
- Source: "devpts",
- Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
- }
- g.AddMount(devPts)
- }
-
- if inUserNS && config.Ipc.IpcMode.IsHost() {
- g.RemoveMount("/dev/mqueue")
- devMqueue := spec.Mount{
- Destination: "/dev/mqueue",
- Type: TypeBind,
- Source: "/dev/mqueue",
- Options: []string{"bind", "nosuid", "noexec", "nodev"},
- }
- g.AddMount(devMqueue)
- }
- if inUserNS && config.Pid.PidMode.IsHost() {
- g.RemoveMount("/proc")
- procMount := spec.Mount{
- Destination: "/proc",
- Type: TypeBind,
- Source: "/proc",
- Options: []string{"rbind", "nosuid", "noexec", "nodev"},
- }
- g.AddMount(procMount)
- }
-
- if addCgroup {
- cgroupMnt := spec.Mount{
- Destination: "/sys/fs/cgroup",
- Type: "cgroup",
- Source: "cgroup",
- Options: []string{"rprivate", "nosuid", "noexec", "nodev", "relatime", cgroupPerm},
- }
- g.AddMount(cgroupMnt)
- }
- g.SetProcessCwd(config.WorkDir)
-
- ProcessArgs := make([]string, 0)
- // We need to iterate the input for entrypoint because it is a []string
- // but "" is a legit json input, which translates into a []string with an
- // empty position. This messes up the eventual command being executed
- // in the container
- for _, a := range config.Entrypoint {
- if len(a) > 0 {
- ProcessArgs = append(ProcessArgs, a)
- }
- }
- // Same issue as explained above for config.Entrypoint.
- for _, a := range config.Command {
- if len(a) > 0 {
- ProcessArgs = append(ProcessArgs, a)
- }
- }
-
- g.SetProcessArgs(ProcessArgs)
- g.SetProcessTerminal(config.Tty)
-
- for key, val := range config.Annotations {
- g.AddAnnotation(key, val)
- }
-
- addedResources := false
-
- // RESOURCES - MEMORY
- if config.Resources.Memory != 0 {
- g.SetLinuxResourcesMemoryLimit(config.Resources.Memory)
- // If a swap limit is not explicitly set, also set a swap limit
- // Default to double the memory limit
- if config.Resources.MemorySwap == 0 {
- g.SetLinuxResourcesMemorySwap(2 * config.Resources.Memory)
- }
- addedResources = true
- }
- if config.Resources.MemoryReservation != 0 {
- g.SetLinuxResourcesMemoryReservation(config.Resources.MemoryReservation)
- addedResources = true
- }
- if config.Resources.MemorySwap != 0 {
- g.SetLinuxResourcesMemorySwap(config.Resources.MemorySwap)
- addedResources = true
- }
- if config.Resources.KernelMemory != 0 {
- g.SetLinuxResourcesMemoryKernel(config.Resources.KernelMemory)
- addedResources = true
- }
- if config.Resources.MemorySwappiness != -1 {
- g.SetLinuxResourcesMemorySwappiness(uint64(config.Resources.MemorySwappiness))
- addedResources = true
- }
- g.SetLinuxResourcesMemoryDisableOOMKiller(config.Resources.DisableOomKiller)
- g.SetProcessOOMScoreAdj(config.Resources.OomScoreAdj)
-
- // RESOURCES - CPU
- if config.Resources.CPUShares != 0 {
- g.SetLinuxResourcesCPUShares(config.Resources.CPUShares)
- addedResources = true
- }
- if config.Resources.CPUQuota != 0 {
- g.SetLinuxResourcesCPUQuota(config.Resources.CPUQuota)
- addedResources = true
- }
- if config.Resources.CPUPeriod != 0 {
- g.SetLinuxResourcesCPUPeriod(config.Resources.CPUPeriod)
- addedResources = true
- }
- if config.Resources.CPUs != 0 {
- g.SetLinuxResourcesCPUPeriod(CpuPeriod)
- g.SetLinuxResourcesCPUQuota(int64(config.Resources.CPUs * CpuPeriod))
- addedResources = true
- }
- if config.Resources.CPURtRuntime != 0 {
- g.SetLinuxResourcesCPURealtimeRuntime(config.Resources.CPURtRuntime)
- addedResources = true
- }
- if config.Resources.CPURtPeriod != 0 {
- g.SetLinuxResourcesCPURealtimePeriod(config.Resources.CPURtPeriod)
- addedResources = true
- }
- if config.Resources.CPUsetCPUs != "" {
- g.SetLinuxResourcesCPUCpus(config.Resources.CPUsetCPUs)
- addedResources = true
- }
- if config.Resources.CPUsetMems != "" {
- g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems)
- addedResources = true
- }
-
- // Devices
- if config.Security.Privileged {
- // If privileged, we need to add all the host devices to the
- // spec. We do not add the user provided ones because we are
- // already adding them all.
- if err := AddPrivilegedDevices(&g); err != nil {
- return nil, err
- }
- } else {
- for _, devicePath := range config.Devices {
- if err := DevicesFromPath(&g, devicePath); err != nil {
- return nil, err
- }
- }
- if len(config.Resources.DeviceCgroupRules) != 0 {
- if err := deviceCgroupRules(&g, config.Resources.DeviceCgroupRules); err != nil {
- return nil, err
- }
- addedResources = true
- }
- }
-
- g.SetProcessNoNewPrivileges(config.Security.NoNewPrivs)
-
- if !config.Security.Privileged {
- g.SetProcessApparmorProfile(config.Security.ApparmorProfile)
- }
-
- // Unless already set via the CLI, check if we need to disable process
- // labels or set the defaults.
- if len(config.Security.LabelOpts) == 0 && runtimeConfig != nil {
- if !runtimeConfig.Containers.EnableLabeling {
- // Disabled in the config.
- config.Security.LabelOpts = append(config.Security.LabelOpts, "disable")
- } else if err := config.Security.SetLabelOpts(runtime, &config.Pid, &config.Ipc); err != nil {
- // Defaults!
- return nil, err
- }
- }
-
- BlockAccessToKernelFilesystems(config.Security.Privileged, config.Pid.PidMode.IsHost(), &g)
-
- // RESOURCES - PIDS
- if config.Resources.PidsLimit > 0 {
- // if running on rootless on a cgroupv1 machine or using the cgroupfs manager, pids
- // limit is not supported. If the value is still the default
- // then ignore the settings. If the caller asked for a
- // non-default, then try to use it.
- setPidLimit := true
- if rootless.IsRootless() {
- cgroup2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return nil, err
- }
- if (!cgroup2 || (runtimeConfig != nil && runtimeConfig.Engine.CgroupManager != cconfig.SystemdCgroupsManager)) && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() {
- setPidLimit = false
- }
- }
- if setPidLimit {
- g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit)
- addedResources = true
- }
- }
-
- // Make sure to always set the default variables unless overridden in the
- // config.
- var defaultEnv map[string]string
- if runtimeConfig == nil {
- defaultEnv = env.DefaultEnvVariables()
- } else {
- defaultEnv, err = env.ParseSlice(runtimeConfig.Containers.Env)
- if err != nil {
- return nil, errors.Wrap(err, "Env fields in containers.conf failed to parse")
- }
- defaultEnv = env.Join(env.DefaultEnvVariables(), defaultEnv)
- }
-
- if err := addRlimits(config, &g); err != nil {
- return nil, err
- }
-
- // NAMESPACES
-
- if err := config.Pid.ConfigureGenerator(&g); err != nil {
- return nil, err
- }
-
- if err := config.User.ConfigureGenerator(&g); err != nil {
- return nil, err
- }
-
- if err := config.Network.ConfigureGenerator(&g); err != nil {
- return nil, err
- }
-
- if err := config.Uts.ConfigureGenerator(&g, &config.Network, runtime); err != nil {
- return nil, err
- }
-
- if err := config.Ipc.ConfigureGenerator(&g); err != nil {
- return nil, err
- }
-
- if err := config.Cgroup.ConfigureGenerator(&g); err != nil {
- return nil, err
- }
-
- config.Env = env.Join(defaultEnv, config.Env)
- for name, val := range config.Env {
- g.AddProcessEnv(name, val)
- }
- 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
- }
-
- // BIND MOUNTS
- configSpec.Mounts = SupercedeUserMounts(userMounts, configSpec.Mounts)
- // Process mounts to ensure correct options
- if err := InitFSMounts(configSpec.Mounts); err != nil {
- return nil, err
- }
-
- // BLOCK IO
- blkio, err := config.CreateBlockIO()
- if err != nil {
- return nil, errors.Wrapf(err, "error creating block io")
- }
- if blkio != nil {
- configSpec.Linux.Resources.BlockIO = blkio
- addedResources = true
- }
-
- if rootless.IsRootless() {
- cgroup2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return nil, err
- }
- if !addedResources {
- configSpec.Linux.Resources = &spec.LinuxResources{}
- }
-
- canUseResources := cgroup2 && runtimeConfig != nil && (runtimeConfig.Engine.CgroupManager == cconfig.SystemdCgroupsManager)
-
- if addedResources && !canUseResources {
- return nil, errors.New("invalid configuration, cannot specify resource limits without cgroups v2 and --cgroup-manager=systemd")
- }
- if !canUseResources {
- // Force the resources block to be empty instead of having default values.
- configSpec.Linux.Resources = &spec.LinuxResources{}
- }
- }
-
- switch config.Cgroup.Cgroups {
- case "disabled":
- if addedResources {
- return nil, errors.New("cannot specify resource limits when cgroups are disabled is specified")
- }
- configSpec.Linux.Resources = &spec.LinuxResources{}
- case "enabled", "no-conmon", "":
- // Do nothing
- default:
- return nil, errors.New("unrecognized option for cgroups; supported are 'default', 'disabled', 'no-conmon'")
- }
-
- // Add annotations
- if configSpec.Annotations == nil {
- configSpec.Annotations = make(map[string]string)
- }
-
- if config.CidFile != "" {
- configSpec.Annotations[define.InspectAnnotationCIDFile] = config.CidFile
- }
-
- if config.Rm {
- configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
- } else {
- configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
- }
-
- if len(config.VolumesFrom) > 0 {
- configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",")
- }
-
- if config.Security.Privileged {
- configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
- } else {
- configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
- }
-
- if config.Init {
- configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
- } else {
- configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
- }
-
- return configSpec, nil
-}
-
-func (config *CreateConfig) cgroupDisabled() bool {
- return config.Cgroup.Cgroups == "disabled"
-}
-
-func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, g *generate.Generator) {
- if !privileged {
- for _, mp := range []string{
- "/proc/acpi",
- "/proc/kcore",
- "/proc/keys",
- "/proc/latency_stats",
- "/proc/timer_list",
- "/proc/timer_stats",
- "/proc/sched_debug",
- "/proc/scsi",
- "/sys/firmware",
- "/sys/fs/selinux",
- } {
- g.AddLinuxMaskedPaths(mp)
- }
-
- if pidModeIsHost && rootless.IsRootless() {
- return
- }
-
- for _, rp := range []string{
- "/proc/asound",
- "/proc/bus",
- "/proc/fs",
- "/proc/irq",
- "/proc/sys",
- "/proc/sysrq-trigger",
- } {
- g.AddLinuxReadonlyPaths(rp)
- }
- }
-}
-
-func addRlimits(config *CreateConfig, g *generate.Generator) error {
- var (
- isRootless = rootless.IsRootless()
- nofileSet = false
- nprocSet = false
- )
-
- for _, u := range config.Resources.Ulimit {
- if u == "host" {
- if len(config.Resources.Ulimit) != 1 {
- return errors.New("ulimit can use host only once")
- }
- g.Config.Process.Rlimits = nil
- break
- }
-
- ul, err := units.ParseUlimit(u)
- if err != nil {
- return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u)
- }
-
- if ul.Name == "nofile" {
- nofileSet = true
- } else if ul.Name == "nproc" {
- nprocSet = true
- }
-
- g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft))
- }
-
- // If not explicitly overridden by the user, default number of open
- // files and number of processes to the maximum they can be set to
- // (without overriding a sysctl)
- if !nofileSet {
- max := define.RLimitDefaultValue
- current := define.RLimitDefaultValue
- if isRootless {
- var rlimit unix.Rlimit
- if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit); err != nil {
- logrus.Warnf("failed to return RLIMIT_NOFILE ulimit %q", err)
- }
- if rlimit.Cur < current {
- current = rlimit.Cur
- }
- if rlimit.Max < max {
- max = rlimit.Max
- }
- }
- g.AddProcessRlimits("RLIMIT_NOFILE", max, current)
- }
- if !nprocSet {
- max := define.RLimitDefaultValue
- current := define.RLimitDefaultValue
- if isRootless {
- var rlimit unix.Rlimit
- if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlimit); err != nil {
- logrus.Warnf("failed to return RLIMIT_NPROC ulimit %q", err)
- }
- if rlimit.Cur < current {
- current = rlimit.Cur
- }
- if rlimit.Max < max {
- max = rlimit.Max
- }
- }
- g.AddProcessRlimits("RLIMIT_NPROC", max, current)
- }
-
- return nil
-}
diff --git a/pkg/spec/spec_test.go b/pkg/spec/spec_test.go
deleted file mode 100644
index d01102fa2..000000000
--- a/pkg/spec/spec_test.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package createconfig
-
-import (
- "runtime"
- "testing"
-
- "github.com/containers/common/pkg/sysinfo"
- "github.com/containers/podman/v2/pkg/cgroups"
- "github.com/containers/podman/v2/pkg/rootless"
- "github.com/containers/storage"
- "github.com/containers/storage/pkg/idtools"
- "github.com/docker/go-units"
- "github.com/stretchr/testify/assert"
-)
-
-var (
- sysInfo = sysinfo.New(true)
-)
-
-// Make createconfig to test with
-func makeTestCreateConfig() *CreateConfig {
- cc := new(CreateConfig)
- cc.Resources = CreateResourceConfig{}
- cc.User.IDMappings = new(storage.IDMappingOptions)
- cc.User.IDMappings.UIDMap = []idtools.IDMap{}
- cc.User.IDMappings.GIDMap = []idtools.IDMap{}
-
- return cc
-}
-
-func doCommonSkipChecks(t *testing.T) {
- // The default configuration of podman enables seccomp, which is not available on non-Linux systems.
- // Thus, any tests that use the default seccomp setting would fail.
- // Skip the tests on non-Linux platforms rather than explicitly disable seccomp in the test and possibly affect the test result.
- if runtime.GOOS != "linux" {
- t.Skip("seccomp, which is enabled by default, is only supported on Linux")
- }
-
- if rootless.IsRootless() {
- isCgroupV2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
-
- if !isCgroupV2 {
- t.Skip("cgroups v1 cannot be used when rootless")
- }
- }
-}
-
-// TestPIDsLimit verifies the given pid-limit is correctly defined in the spec
-func TestPIDsLimit(t *testing.T) {
- doCommonSkipChecks(t)
-
- if !sysInfo.PidsLimit {
- t.Skip("running test not supported by the host system")
- }
-
- cc := makeTestCreateConfig()
- cc.Resources.PidsLimit = 22
-
- spec, err := cc.createConfigToOCISpec(nil, nil)
- assert.NoError(t, err)
-
- assert.Equal(t, spec.Linux.Resources.Pids.Limit, int64(22))
-}
-
-// TestBLKIOWeightDevice verifies the given blkio weight is correctly set in the
-// spec.
-func TestBLKIOWeightDevice(t *testing.T) {
- doCommonSkipChecks(t)
-
- if !sysInfo.BlkioWeightDevice {
- t.Skip("running test not supported by the host system")
- }
-
- cc := makeTestCreateConfig()
- cc.Resources.BlkioWeightDevice = []string{"/dev/zero:100"}
-
- spec, err := cc.createConfigToOCISpec(nil, nil)
- assert.NoError(t, err)
-
- // /dev/zero is guaranteed 1,5 by the Linux kernel
- assert.Equal(t, spec.Linux.Resources.BlockIO.WeightDevice[0].Major, int64(1))
- assert.Equal(t, spec.Linux.Resources.BlockIO.WeightDevice[0].Minor, int64(5))
- assert.Equal(t, *(spec.Linux.Resources.BlockIO.WeightDevice[0].Weight), uint16(100))
-}
-
-// TestMemorySwap verifies that the given swap memory limit is correctly set in
-// the spec.
-func TestMemorySwap(t *testing.T) {
- doCommonSkipChecks(t)
-
- if !sysInfo.SwapLimit {
- t.Skip("running test not supported by the host system")
- }
-
- swapLimit, err := units.RAMInBytes("45m")
- assert.NoError(t, err)
-
- cc := makeTestCreateConfig()
- cc.Resources.MemorySwap = swapLimit
-
- spec, err := cc.createConfigToOCISpec(nil, nil)
- assert.NoError(t, err)
-
- assert.Equal(t, *(spec.Linux.Resources.Memory.Swap), swapLimit)
-}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
deleted file mode 100644
index b441daf08..000000000
--- a/pkg/spec/storage.go
+++ /dev/null
@@ -1,875 +0,0 @@
-package createconfig
-
-import (
- "fmt"
- "os"
- "path"
- "path/filepath"
- "strings"
-
- "github.com/containers/buildah/pkg/parse"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/pkg/util"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-const (
- // TypeBind is the type for mounting host dir
- TypeBind = "bind"
- // TypeVolume is the type for named volumes
- TypeVolume = "volume"
- // TypeTmpfs is the type for mounting tmpfs
- TypeTmpfs = "tmpfs"
-)
-
-var (
- errDuplicateDest = errors.Errorf("duplicate mount destination")
- optionArgError = errors.Errorf("must provide an argument for option")
- noDestError = errors.Errorf("must set volume destination")
-)
-
-// Parse all volume-related options in the create config into a set of mounts
-// and named volumes to add to the container.
-// Handles --volumes-from, --volumes, --tmpfs, --init, and --init-path flags.
-// TODO: Named volume options - should we default to rprivate? It bakes into a
-// bind mount under the hood...
-// TODO: handle options parsing/processing via containers/storage/pkg/mount
-func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount, []*libpod.ContainerNamedVolume, error) {
- // Add image volumes.
- baseMounts, baseVolumes, err := config.getImageVolumes()
- if err != nil {
- return nil, nil, err
- }
-
- // Add --volumes-from.
- // Overrides image volumes unconditionally.
- vFromMounts, vFromVolumes, err := config.getVolumesFrom(runtime)
- if err != nil {
- return nil, nil, err
- }
- for dest, mount := range vFromMounts {
- baseMounts[dest] = mount
- }
- for dest, volume := range vFromVolumes {
- baseVolumes[dest] = volume
- }
-
- // Next mounts from the --mounts flag.
- // Do not override yet.
- unifiedMounts, unifiedVolumes, err := config.getMounts()
- if err != nil {
- return nil, nil, err
- }
-
- // Next --volumes flag.
- // Do not override yet.
- volumeMounts, volumeVolumes, err := config.getVolumeMounts()
- if err != nil {
- return nil, nil, err
- }
-
- // Next --tmpfs flag.
- // Do not override yet.
- tmpfsMounts, err := config.getTmpfsMounts()
- if err != nil {
- return nil, nil, err
- }
-
- // Unify mounts from --mount, --volume, --tmpfs.
- // Also add mounts + volumes directly from createconfig.
- // Start with --volume.
- for dest, mount := range volumeMounts {
- if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedMounts[dest] = mount
- }
- for dest, volume := range volumeVolumes {
- if _, ok := unifiedVolumes[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedVolumes[dest] = volume
- }
- // Now --tmpfs
- for dest, tmpfs := range tmpfsMounts {
- if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedMounts[dest] = tmpfs
- }
- // Now spec mounts and volumes
- for _, mount := range config.Mounts {
- dest := mount.Destination
- if _, ok := unifiedMounts[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedMounts[dest] = mount
- }
- for _, volume := range config.NamedVolumes {
- dest := volume.Dest
- if _, ok := unifiedVolumes[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, dest)
- }
- unifiedVolumes[dest] = volume
- }
-
- // If requested, add container init binary
- if config.Init {
- initPath := config.InitPath
- if initPath == "" {
- rtc, err := runtime.GetConfig()
- if err != nil {
- return nil, nil, err
- }
- initPath = rtc.Engine.InitPath
- }
- initMount, err := config.addContainerInitBinary(initPath)
- if err != nil {
- return nil, nil, err
- }
- if _, ok := unifiedMounts[initMount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
- }
- unifiedMounts[initMount.Destination] = initMount
- }
-
- // Before superseding, we need to find volume mounts which conflict with
- // named volumes, and vice versa.
- // We'll delete the conflicts here as we supersede.
- for dest := range unifiedMounts {
- if _, ok := baseVolumes[dest]; ok {
- delete(baseVolumes, dest)
- }
- }
- for dest := range unifiedVolumes {
- if _, ok := baseMounts[dest]; ok {
- delete(baseMounts, dest)
- }
- }
-
- // Supersede volumes-from/image volumes with unified volumes from above.
- // This is an unconditional replacement.
- for dest, mount := range unifiedMounts {
- baseMounts[dest] = mount
- }
- for dest, volume := range unifiedVolumes {
- baseVolumes[dest] = volume
- }
-
- // If requested, add tmpfs filesystems for read-only containers.
- if config.Security.ReadOnlyRootfs && config.Security.ReadOnlyTmpfs {
- readonlyTmpfs := []string{"/tmp", "/var/tmp", "/run"}
- options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"}
- for _, dest := range readonlyTmpfs {
- if _, ok := baseMounts[dest]; ok {
- continue
- }
- if _, ok := baseVolumes[dest]; ok {
- continue
- }
- localOpts := options
- if dest == "/run" {
- localOpts = append(localOpts, "noexec", "size=65536k")
- } else {
- localOpts = append(localOpts, "exec")
- }
- baseMounts[dest] = spec.Mount{
- Destination: dest,
- Type: "tmpfs",
- Source: "tmpfs",
- Options: localOpts,
- }
- }
- }
-
- // Check for conflicts between named volumes and mounts
- for dest := range baseMounts {
- if _, ok := baseVolumes[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
- }
- }
- for dest := range baseVolumes {
- if _, ok := baseMounts[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
- }
- }
-
- // Final step: maps to arrays
- finalMounts := make([]spec.Mount, 0, len(baseMounts))
- for _, mount := range baseMounts {
- if mount.Type == TypeBind {
- absSrc, err := filepath.Abs(mount.Source)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
- }
- mount.Source = absSrc
- }
- finalMounts = append(finalMounts, mount)
- }
- finalVolumes := make([]*libpod.ContainerNamedVolume, 0, len(baseVolumes))
- for _, volume := range baseVolumes {
- finalVolumes = append(finalVolumes, volume)
- }
-
- return finalMounts, finalVolumes, nil
-}
-
-// Parse volumes from - a set of containers whose volumes we will mount in.
-// Grab the containers, retrieve any user-created spec mounts and all named
-// volumes, and return a list of them.
-// Conflicts are resolved simply - the last container specified wins.
-// Container names may be suffixed by mount options after a colon.
-// TODO: We should clean these paths if possible
-func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
- // Both of these are maps of mount destination to mount type.
- // We ensure that each destination is only mounted to once in this way.
- finalMounts := make(map[string]spec.Mount)
- finalNamedVolumes := make(map[string]*libpod.ContainerNamedVolume)
-
- for _, vol := range config.VolumesFrom {
- var (
- options = []string{}
- err error
- splitVol = strings.SplitN(vol, ":", 2)
- )
- if len(splitVol) == 2 {
- splitOpts := strings.Split(splitVol[1], ",")
- for _, checkOpt := range splitOpts {
- switch checkOpt {
- case "z", "ro", "rw":
- // Do nothing, these are valid options
- default:
- return nil, nil, errors.Errorf("invalid options %q, can only specify 'ro', 'rw', and 'z'", splitVol[1])
- }
- }
-
- if options, err = parse.ValidateVolumeOpts(splitOpts); err != nil {
- return nil, nil, err
- }
- }
- ctr, err := runtime.LookupContainer(splitVol[0])
- if err != nil {
- return nil, nil, errors.Wrapf(err, "error looking up container %q for volumes-from", splitVol[0])
- }
-
- logrus.Debugf("Adding volumes from container %s", ctr.ID())
-
- // Look up the container's user volumes. This gets us the
- // destinations of all mounts the user added to the container.
- userVolumesArr := ctr.UserVolumes()
-
- // We're going to need to access them a lot, so convert to a map
- // to reduce looping.
- // We'll also use the map to indicate if we missed any volumes along the way.
- userVolumes := make(map[string]bool)
- for _, dest := range userVolumesArr {
- userVolumes[dest] = false
- }
-
- // Now we get the container's spec and loop through its volumes
- // and append them in if we can find them.
- spec := ctr.Spec()
- if spec == nil {
- return nil, nil, errors.Errorf("error retrieving container %s spec for volumes-from", ctr.ID())
- }
- for _, mnt := range spec.Mounts {
- if mnt.Type != TypeBind {
- continue
- }
- if _, exists := userVolumes[mnt.Destination]; exists {
- userVolumes[mnt.Destination] = true
-
- if len(options) != 0 {
- mnt.Options = options
- }
-
- if _, ok := finalMounts[mnt.Destination]; ok {
- logrus.Debugf("Overriding mount to %s with new mount from container %s", mnt.Destination, ctr.ID())
- }
- finalMounts[mnt.Destination] = mnt
- }
- }
-
- // We're done with the spec mounts. Add named volumes.
- // Add these unconditionally - none of them are automatically
- // part of the container, as some spec mounts are.
- namedVolumes := ctr.NamedVolumes()
- for _, namedVol := range namedVolumes {
- if _, exists := userVolumes[namedVol.Dest]; exists {
- userVolumes[namedVol.Dest] = true
- }
-
- if len(options) != 0 {
- namedVol.Options = options
- }
-
- if _, ok := finalMounts[namedVol.Dest]; ok {
- logrus.Debugf("Overriding named volume mount to %s with new named volume from container %s", namedVol.Dest, ctr.ID())
- }
- finalNamedVolumes[namedVol.Dest] = namedVol
- }
-
- // Check if we missed any volumes
- for volDest, found := range userVolumes {
- if !found {
- logrus.Warnf("Unable to match volume %s from container %s for volumes-from", volDest, ctr.ID())
- }
- }
- }
-
- return finalMounts, finalNamedVolumes, nil
-}
-
-// getMounts takes user-provided input from the --mount flag and creates OCI
-// spec mounts and Libpod named volumes.
-// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ...
-// podman run --mount type=tmpfs,target=/dev/shm ...
-// podman run --mount type=volume,source=test-volume, ...
-func (config *CreateConfig) getMounts() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
- finalMounts := make(map[string]spec.Mount)
- finalNamedVolumes := make(map[string]*libpod.ContainerNamedVolume)
-
- errInvalidSyntax := errors.Errorf("incorrect mount format: should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]")
-
- // TODO(vrothberg): the manual parsing can be replaced with a regular expression
- // to allow a more robust parsing of the mount format and to give
- // precise errors regarding supported format versus supported options.
- for _, mount := range config.MountsFlag {
- arr := strings.SplitN(mount, ",", 2)
- if len(arr) < 2 {
- return nil, nil, errors.Wrapf(errInvalidSyntax, "%q", mount)
- }
- kv := strings.Split(arr[0], "=")
- // TODO: type is not explicitly required in Docker.
- // If not specified, it defaults to "volume".
- if len(kv) != 2 || kv[0] != "type" {
- return nil, nil, errors.Wrapf(errInvalidSyntax, "%q", mount)
- }
-
- tokens := strings.Split(arr[1], ",")
- switch kv[1] {
- case TypeBind:
- mount, err := getBindMount(tokens)
- if err != nil {
- return nil, nil, err
- }
- if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
- }
- finalMounts[mount.Destination] = mount
- case TypeTmpfs:
- mount, err := getTmpfsMount(tokens)
- if err != nil {
- return nil, nil, err
- }
- if _, ok := finalMounts[mount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination)
- }
- finalMounts[mount.Destination] = mount
- case "volume":
- volume, err := getNamedVolume(tokens)
- if err != nil {
- return nil, nil, err
- }
- if _, ok := finalNamedVolumes[volume.Dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, volume.Dest)
- }
- finalNamedVolumes[volume.Dest] = volume
- default:
- return nil, nil, errors.Errorf("invalid filesystem type %q", kv[1])
- }
- }
-
- return finalMounts, finalNamedVolumes, nil
-}
-
-// Parse a single bind mount entry from the --mount flag.
-func getBindMount(args []string) (spec.Mount, error) {
- newMount := spec.Mount{
- Type: TypeBind,
- }
-
- var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "bind-nonrecursive":
- newMount.Options = append(newMount.Options, "bind")
- case "ro", "rw":
- if setRORW {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' or 'rw' options more than once")
- }
- setRORW = true
- // Can be formatted as one of:
- // ro
- // ro=[true|false]
- // rw
- // rw=[true|false]
- switch len(kv) {
- case 1:
- newMount.Options = append(newMount.Options, kv[0])
- case 2:
- switch strings.ToLower(kv[1]) {
- case "true":
- newMount.Options = append(newMount.Options, kv[0])
- case "false":
- // Set the opposite only for rw
- // ro's opposite is the default
- if kv[0] == "rw" {
- newMount.Options = append(newMount.Options, "ro")
- }
- default:
- return newMount, errors.Wrapf(optionArgError, "%s must be set to true or false, instead received %q", kv[0], kv[1])
- }
- default:
- return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val)
- }
- case "nosuid", "suid":
- if setSuid {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
- }
- setSuid = true
- newMount.Options = append(newMount.Options, kv[0])
- case "nodev", "dev":
- if setDev {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once")
- }
- setDev = true
- newMount.Options = append(newMount.Options, kv[0])
- case "noexec", "exec":
- if setExec {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once")
- }
- setExec = true
- newMount.Options = append(newMount.Options, kv[0])
- case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z":
- newMount.Options = append(newMount.Options, kv[0])
- case "bind-propagation":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- newMount.Options = append(newMount.Options, kv[1])
- case "src", "source":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeHostDir(kv[1]); err != nil {
- return newMount, err
- }
- newMount.Source = kv[1]
- setSource = true
- case "target", "dst", "destination":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
- return newMount, err
- }
- newMount.Destination = filepath.Clean(kv[1])
- setDest = true
- case "relabel":
- if setRelabel {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'relabel' option more than once")
- }
- setRelabel = true
- if len(kv) != 2 {
- return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0])
- }
- switch kv[1] {
- case "private":
- newMount.Options = append(newMount.Options, "z")
- case "shared":
- newMount.Options = append(newMount.Options, "Z")
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0])
- }
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setDest {
- return newMount, noDestError
- }
-
- if !setSource {
- newMount.Source = newMount.Destination
- }
-
- options, err := parse.ValidateVolumeOpts(newMount.Options)
- if err != nil {
- return newMount, err
- }
- newMount.Options = options
- return newMount, nil
-}
-
-// Parse a single tmpfs mount entry from the --mount flag
-func getTmpfsMount(args []string) (spec.Mount, error) {
- newMount := spec.Mount{
- Type: TypeTmpfs,
- Source: TypeTmpfs,
- }
-
- var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "tmpcopyup", "notmpcopyup":
- if setTmpcopyup {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'tmpcopyup' and 'notmpcopyup' options more than once")
- }
- setTmpcopyup = true
- newMount.Options = append(newMount.Options, kv[0])
- case "ro", "rw":
- if setRORW {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once")
- }
- setRORW = true
- newMount.Options = append(newMount.Options, kv[0])
- case "nosuid", "suid":
- if setSuid {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
- }
- setSuid = true
- newMount.Options = append(newMount.Options, kv[0])
- case "nodev", "dev":
- if setDev {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once")
- }
- setDev = true
- newMount.Options = append(newMount.Options, kv[0])
- case "noexec", "exec":
- if setExec {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once")
- }
- setExec = true
- newMount.Options = append(newMount.Options, kv[0])
- case "tmpfs-mode":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- newMount.Options = append(newMount.Options, fmt.Sprintf("mode=%s", kv[1]))
- case "tmpfs-size":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- newMount.Options = append(newMount.Options, fmt.Sprintf("size=%s", kv[1]))
- case "src", "source":
- return newMount, errors.Errorf("source is not supported with tmpfs mounts")
- case "target", "dst", "destination":
- if len(kv) == 1 {
- return newMount, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
- return newMount, err
- }
- newMount.Destination = filepath.Clean(kv[1])
- setDest = true
- default:
- return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setDest {
- return newMount, noDestError
- }
-
- return newMount, nil
-}
-
-// Parse a single volume mount entry from the --mount flag.
-// Note that the volume-label option for named volumes is currently NOT supported.
-// TODO: add support for --volume-label
-func getNamedVolume(args []string) (*libpod.ContainerNamedVolume, error) {
- newVolume := new(libpod.ContainerNamedVolume)
-
- var setSource, setDest, setRORW, setSuid, setDev, setExec bool
-
- for _, val := range args {
- kv := strings.SplitN(val, "=", 2)
- switch kv[0] {
- case "ro", "rw":
- if setRORW {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once")
- }
- setRORW = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "nosuid", "suid":
- if setSuid {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once")
- }
- setSuid = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "nodev", "dev":
- if setDev {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once")
- }
- setDev = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "noexec", "exec":
- if setExec {
- return nil, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once")
- }
- setExec = true
- newVolume.Options = append(newVolume.Options, kv[0])
- case "volume-label":
- return nil, errors.Errorf("the --volume-label option is not presently implemented")
- case "src", "source":
- if len(kv) == 1 {
- return nil, errors.Wrapf(optionArgError, kv[0])
- }
- newVolume.Name = kv[1]
- setSource = true
- case "target", "dst", "destination":
- if len(kv) == 1 {
- return nil, errors.Wrapf(optionArgError, kv[0])
- }
- if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
- return nil, err
- }
- newVolume.Dest = filepath.Clean(kv[1])
- setDest = true
- default:
- return nil, errors.Wrapf(util.ErrBadMntOption, kv[0])
- }
- }
-
- if !setSource {
- return nil, errors.Errorf("must set source volume")
- }
- if !setDest {
- return nil, noDestError
- }
-
- return newVolume, nil
-}
-
-func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
- mounts := make(map[string]spec.Mount)
- volumes := make(map[string]*libpod.ContainerNamedVolume)
-
- volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
-
- for _, vol := range config.Volumes {
- var (
- options []string
- src string
- dest string
- err error
- )
-
- splitVol := strings.Split(vol, ":")
- if len(splitVol) > 3 {
- return nil, nil, errors.Wrapf(volumeFormatErr, vol)
- }
-
- src = splitVol[0]
- if len(splitVol) == 1 {
- // This is an anonymous named volume. Only thing given
- // is destination.
- // Name/source will be blank, and populated by libpod.
- src = ""
- dest = splitVol[0]
- } else if len(splitVol) > 1 {
- dest = splitVol[1]
- }
- if len(splitVol) > 2 {
- if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
- return nil, nil, err
- }
- }
-
- // Do not check source dir for anonymous volumes
- if len(splitVol) > 1 {
- if err := parse.ValidateVolumeHostDir(src); err != nil {
- return nil, nil, err
- }
- }
- if err := parse.ValidateVolumeCtrDir(dest); err != nil {
- return nil, nil, err
- }
-
- cleanDest := filepath.Clean(dest)
-
- if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
- // This is not a named volume
- newMount := spec.Mount{
- Destination: cleanDest,
- Type: string(TypeBind),
- Source: src,
- Options: options,
- }
- if _, ok := mounts[newMount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination)
- }
- mounts[newMount.Destination] = newMount
- } else {
- // This is a named volume
- newNamedVol := new(libpod.ContainerNamedVolume)
- newNamedVol.Name = src
- newNamedVol.Dest = cleanDest
- newNamedVol.Options = options
-
- if _, ok := volumes[newNamedVol.Dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest)
- }
- volumes[newNamedVol.Dest] = newNamedVol
- }
-
- logrus.Debugf("User mount %s:%s options %v", src, dest, options)
- }
-
- return mounts, volumes, nil
-}
-
-// Get mounts for container's image volumes
-func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
- mounts := make(map[string]spec.Mount)
- volumes := make(map[string]*libpod.ContainerNamedVolume)
-
- if config.ImageVolumeType == "ignore" {
- return mounts, volumes, nil
- }
-
- for vol := range config.BuiltinImgVolumes {
- cleanDest := filepath.Clean(vol)
- logrus.Debugf("Adding image volume at %s", cleanDest)
- if config.ImageVolumeType == "tmpfs" {
- // Tmpfs image volumes are handled as mounts
- mount := spec.Mount{
- Destination: cleanDest,
- Source: TypeTmpfs,
- Type: TypeTmpfs,
- Options: []string{"rprivate", "rw", "nodev", "exec"},
- }
- mounts[cleanDest] = mount
- } else {
- // Anonymous volumes have no name.
- namedVolume := new(libpod.ContainerNamedVolume)
- namedVolume.Options = []string{"rprivate", "rw", "nodev", "exec"}
- namedVolume.Dest = cleanDest
- volumes[cleanDest] = namedVolume
- }
- }
-
- return mounts, volumes, nil
-}
-
-// GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts
-func (config *CreateConfig) getTmpfsMounts() (map[string]spec.Mount, error) {
- m := make(map[string]spec.Mount)
- for _, i := range config.Tmpfs {
- // Default options if nothing passed
- var options []string
- spliti := strings.Split(i, ":")
- destPath := spliti[0]
- if err := parse.ValidateVolumeCtrDir(spliti[0]); err != nil {
- return nil, err
- }
- if len(spliti) > 1 {
- options = strings.Split(spliti[1], ",")
- }
-
- if _, ok := m[destPath]; ok {
- return nil, errors.Wrapf(errDuplicateDest, destPath)
- }
-
- mount := spec.Mount{
- Destination: filepath.Clean(destPath),
- Type: string(TypeTmpfs),
- Options: options,
- Source: string(TypeTmpfs),
- }
- m[destPath] = mount
- }
- return m, nil
-}
-
-// AddContainerInitBinary adds the init binary specified by path iff the
-// container will run in a private PID namespace that is not shared with the
-// host or another pre-existing container, where an init-like process is
-// already running.
-//
-// Note that AddContainerInitBinary prepends "/dev/init" "--" to the command
-// to execute the bind-mounted binary as PID 1.
-func (config *CreateConfig) addContainerInitBinary(path string) (spec.Mount, error) {
- mount := spec.Mount{
- Destination: "/dev/init",
- Type: TypeBind,
- Source: path,
- Options: []string{TypeBind, "ro"},
- }
-
- if path == "" {
- return mount, fmt.Errorf("please specify a path to the container-init binary")
- }
- if !config.Pid.PidMode.IsPrivate() {
- return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
- }
- if config.Systemd {
- return mount, fmt.Errorf("cannot use container-init binary with systemd")
- }
- if _, err := os.Stat(path); os.IsNotExist(err) {
- return mount, errors.Wrap(err, "container-init binary not found on the host")
- }
- config.Command = append([]string{"/dev/init", "--"}, config.Command...)
- return mount, nil
-}
-
-// Supersede existing mounts in the spec with new, user-specified mounts.
-// TODO: Should we unmount subtree mounts? E.g., if /tmp/ is mounted by
-// one mount, and we already have /tmp/a and /tmp/b, should we remove
-// the /tmp/a and /tmp/b mounts in favor of the more general /tmp?
-func SupercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount {
- if len(mounts) > 0 {
- // If we have overlappings mounts, remove them from the spec in favor of
- // the user-added volume mounts
- destinations := make(map[string]bool)
- for _, mount := range mounts {
- destinations[path.Clean(mount.Destination)] = true
- }
- // Copy all mounts from spec to defaultMounts, except for
- // - mounts overridden by a user supplied mount;
- // - all mounts under /dev if a user supplied /dev is present;
- mountDev := destinations["/dev"]
- for _, mount := range configMount {
- if _, ok := destinations[path.Clean(mount.Destination)]; !ok {
- if mountDev && strings.HasPrefix(mount.Destination, "/dev/") {
- // filter out everything under /dev if /dev is user-mounted
- continue
- }
-
- logrus.Debugf("Adding mount %s", mount.Destination)
- mounts = append(mounts, mount)
- }
- }
- return mounts
- }
- return configMount
-}
-
-// Ensure mount options on all mounts are correct
-func InitFSMounts(mounts []spec.Mount) error {
- for i, m := range mounts {
- switch {
- case m.Type == TypeBind:
- opts, err := util.ProcessOptions(m.Options, false, m.Source)
- if err != nil {
- return err
- }
- mounts[i].Options = opts
- case m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev":
- opts, err := util.ProcessOptions(m.Options, true, "")
- if err != nil {
- return err
- }
- mounts[i].Options = opts
- }
- }
- return nil
-}
diff --git a/pkg/spec/storage_test.go b/pkg/spec/storage_test.go
deleted file mode 100644
index 04a9d6976..000000000
--- a/pkg/spec/storage_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package createconfig
-
-import (
- "testing"
-
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/stretchr/testify/assert"
-)
-
-func TestGetVolumeMountsOneVolume(t *testing.T) {
- data := spec.Mount{
- Destination: "/foobar",
- Type: "bind",
- Source: "/tmp",
- Options: []string{"ro"},
- }
- config := CreateConfig{
- Volumes: []string{"/tmp:/foobar:ro"},
- }
- specMount, _, err := config.getVolumeMounts()
- assert.NoError(t, err)
- assert.EqualValues(t, data, specMount[data.Destination])
-}
-
-func TestGetTmpfsMounts(t *testing.T) {
- data := spec.Mount{
- Destination: "/homer",
- Type: "tmpfs",
- Source: "tmpfs",
- Options: []string{"rw", "size=787448k", "mode=1777"},
- }
- config := CreateConfig{
- Tmpfs: []string{"/homer:rw,size=787448k,mode=1777"},
- }
- tmpfsMount, err := config.getTmpfsMounts()
- assert.NoError(t, err)
- assert.EqualValues(t, data, tmpfsMount[data.Destination])
-}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 2ee8f2441..c7e62d185 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -257,7 +257,19 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
}
- return verifyContainerResources(s)
+ warnings, err := verifyContainerResources(s)
+ if err != nil {
+ return warnings, err
+ }
+
+ // Warn on net=host/container/pod/none and port mappings.
+ if (s.NetNS.NSMode == specgen.Host || s.NetNS.NSMode == specgen.FromContainer ||
+ s.NetNS.NSMode == specgen.FromPod || s.NetNS.NSMode == specgen.NoNetwork) &&
+ len(s.PortMappings) > 0 {
+ warnings = append(warnings, "Port mappings have been discarded as one of the Host, Container, Pod, and None network modes are in use")
+ }
+
+ return warnings, nil
}
// finishThrottleDevices takes the temporary representation of the throttle
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index c049e64cf..45a374216 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -111,7 +111,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, errors.Wrap(err, "invalid config provided")
}
- finalMounts, finalVolumes, err := finalizeMounts(ctx, s, rt, rtc, newImage)
+ finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage)
if err != nil {
return nil, err
}
@@ -121,7 +121,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, err
}
- opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, newImage, command)
+ opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, newImage, command)
if err != nil {
return nil, err
}
@@ -144,7 +144,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return rt.NewContainer(ctx, runtimeSpec, options...)
}
-func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
+func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
var err error
@@ -224,7 +224,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
for _, volume := range volumes {
destinations = append(destinations, volume.Dest)
}
- for _, overlayVolume := range s.OverlayVolumes {
+ for _, overlayVolume := range overlays {
destinations = append(destinations, overlayVolume.Destination)
}
for _, imageVolume := range s.ImageVolumes {
@@ -244,9 +244,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithNamedVolumes(vols))
}
- if len(s.OverlayVolumes) != 0 {
+ if len(overlays) != 0 {
var vols []*libpod.ContainerOverlayVolume
- for _, v := range s.OverlayVolumes {
+ for _, v := range overlays {
vols = append(vols, &libpod.ContainerOverlayVolume{
Dest: v.Destination,
Source: v.Source,
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index e1202956c..5f72d28bb 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -47,7 +47,7 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
return p, nil
}
-func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) {
+func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]*KubeVolume, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) {
s := specgen.NewSpecGenerator(iid, false)
// podName should be non-empty for Deployment objects to be able to create
@@ -163,22 +163,36 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
s.Env = envs
for _, volume := range containerYAML.VolumeMounts {
- hostPath, exists := volumes[volume.Name]
+ volumeSource, exists := volumes[volume.Name]
if !exists {
return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
}
- if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil {
- return nil, errors.Wrapf(err, "error in parsing MountPath")
- }
- mount := spec.Mount{
- Destination: volume.MountPath,
- Source: hostPath,
- Type: "bind",
- }
- if volume.ReadOnly {
- mount.Options = []string{"ro"}
+ switch volumeSource.Type {
+ case KubeVolumeTypeBindMount:
+ if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil {
+ return nil, errors.Wrapf(err, "error in parsing MountPath")
+ }
+ mount := spec.Mount{
+ Destination: volume.MountPath,
+ Source: volumeSource.Source,
+ Type: "bind",
+ }
+ if volume.ReadOnly {
+ mount.Options = []string{"ro"}
+ }
+ s.Mounts = append(s.Mounts, mount)
+ case KubeVolumeTypeNamed:
+ namedVolume := specgen.NamedVolume{
+ Dest: volume.MountPath,
+ Name: volumeSource.Source,
+ }
+ if volume.ReadOnly {
+ namedVolume.Options = []string{"ro"}
+ }
+ s.Volumes = append(s.Volumes, &namedVolume)
+ default:
+ return nil, errors.Errorf("Unsupported volume source type")
}
- s.Mounts = append(s.Mounts, mount)
}
s.RestartPolicy = restartPolicy
diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go
new file mode 100644
index 000000000..2ef0f4c23
--- /dev/null
+++ b/pkg/specgen/generate/kube/volume.go
@@ -0,0 +1,124 @@
+package kube
+
+import (
+ "os"
+
+ "github.com/containers/buildah/pkg/parse"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ v1 "k8s.io/api/core/v1"
+)
+
+const (
+ // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
+ kubeDirectoryPermission = 0755
+ // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
+ kubeFilePermission = 0644
+)
+
+type KubeVolumeType int
+
+const (
+ KubeVolumeTypeBindMount KubeVolumeType = iota
+ KubeVolumeTypeNamed KubeVolumeType = iota
+)
+
+type KubeVolume struct {
+ // Type of volume to create
+ Type KubeVolumeType
+ // Path for bind mount or volume name for named volume
+ Source string
+}
+
+// Create a KubeVolume from an HostPathVolumeSource
+func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error) {
+ if hostPath.Type != nil {
+ switch *hostPath.Type {
+ case v1.HostPathDirectoryOrCreate:
+ if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
+ if err := os.Mkdir(hostPath.Path, kubeDirectoryPermission); err != nil {
+ return nil, err
+ }
+ }
+ // Label a newly created volume
+ if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
+ return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path)
+ }
+ case v1.HostPathFileOrCreate:
+ if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
+ f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission)
+ if err != nil {
+ return nil, errors.Wrap(err, "error creating HostPath")
+ }
+ if err := f.Close(); err != nil {
+ logrus.Warnf("Error in closing newly created HostPath file: %v", err)
+ }
+ }
+ // unconditionally label a newly created volume
+ if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
+ return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path)
+ }
+ case v1.HostPathSocket:
+ st, err := os.Stat(hostPath.Path)
+ if err != nil {
+ return nil, errors.Wrap(err, "error checking HostPathSocket")
+ }
+ if st.Mode()&os.ModeSocket != os.ModeSocket {
+ return nil, errors.Errorf("error checking HostPathSocket: path %s is not a socket", hostPath.Path)
+ }
+
+ case v1.HostPathDirectory:
+ case v1.HostPathFile:
+ case v1.HostPathUnset:
+ // do nothing here because we will verify the path exists in validateVolumeHostDir
+ break
+ default:
+ return nil, errors.Errorf("Invalid HostPath type %v", hostPath.Type)
+ }
+ }
+
+ if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil {
+ return nil, errors.Wrapf(err, "error in parsing HostPath in YAML")
+ }
+
+ return &KubeVolume{
+ Type: KubeVolumeTypeBindMount,
+ Source: hostPath.Path,
+ }, nil
+}
+
+// Create a KubeVolume from a PersistentVolumeClaimVolumeSource
+func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource) (*KubeVolume, error) {
+ return &KubeVolume{
+ Type: KubeVolumeTypeNamed,
+ Source: claim.ClaimName,
+ }, nil
+}
+
+// Create a KubeVolume from one of the supported VolumeSource
+func VolumeFromSource(volumeSource v1.VolumeSource) (*KubeVolume, error) {
+ if volumeSource.HostPath != nil {
+ return VolumeFromHostPath(volumeSource.HostPath)
+ } else if volumeSource.PersistentVolumeClaim != nil {
+ return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim)
+ } else {
+ return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the conly supported VolumeSource")
+ }
+}
+
+// Create a map of volume name to KubeVolume
+func InitializeVolumes(specVolumes []v1.Volume) (map[string]*KubeVolume, error) {
+ volumes := make(map[string]*KubeVolume)
+
+ for _, specVolume := range specVolumes {
+ volume, err := VolumeFromSource(specVolume.VolumeSource)
+ if err != nil {
+ return nil, err
+ }
+
+ volumes[specVolume.Name] = volume
+ }
+
+ return volumes, nil
+}
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index b225f79ee..331a5c5bf 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -33,17 +33,17 @@ var (
)
// Produce final mounts and named volumes for a container
-func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, error) {
+func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) {
// Get image volumes
baseMounts, baseVolumes, err := getImageVolumes(ctx, img, s)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
// Get volumes-from mounts
volFromMounts, volFromVolumes, err := getVolumesFrom(s.VolumesFrom, rt)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
// Supersede from --volumes-from.
@@ -57,19 +57,53 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
// Need to make map forms of specgen mounts/volumes.
unifiedMounts := map[string]spec.Mount{}
unifiedVolumes := map[string]*specgen.NamedVolume{}
+ unifiedOverlays := map[string]*specgen.OverlayVolume{}
+
+ // Need to make map forms of specgen mounts/volumes.
+ commonMounts, commonVolumes, commonOverlayVolumes, err := specgen.GenVolumeMounts(rtc.Volumes())
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
for _, m := range s.Mounts {
if _, ok := unifiedMounts[m.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination)
}
unifiedMounts[m.Destination] = m
}
+
+ for _, m := range commonMounts {
+ if _, ok := unifiedMounts[m.Destination]; !ok {
+ unifiedMounts[m.Destination] = m
+ }
+ }
+
for _, v := range s.Volumes {
if _, ok := unifiedVolumes[v.Dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest)
}
unifiedVolumes[v.Dest] = v
}
+ for _, v := range commonVolumes {
+ if _, ok := unifiedVolumes[v.Dest]; !ok {
+ unifiedVolumes[v.Dest] = v
+ }
+ }
+
+ for _, v := range s.OverlayVolumes {
+ if _, ok := unifiedOverlays[v.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Destination)
+ }
+ unifiedOverlays[v.Destination] = v
+ }
+
+ for _, v := range commonOverlayVolumes {
+ if _, ok := unifiedOverlays[v.Destination]; ok {
+ unifiedOverlays[v.Destination] = v
+ }
+ }
+
// If requested, add container init binary
if s.Init {
initPath := s.InitPath
@@ -78,10 +112,10 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
}
initMount, err := addContainerInitBinary(s, initPath)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
if _, ok := unifiedMounts[initMount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
}
unifiedMounts[initMount.Destination] = initMount
}
@@ -115,12 +149,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
// Check for conflicts between named volumes and mounts
for dest := range baseMounts {
if _, ok := baseVolumes[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
}
}
for dest := range baseVolumes {
if _, ok := baseMounts[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
}
}
// Final step: maps to arrays
@@ -129,7 +163,7 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
if mount.Type == TypeBind {
absSrc, err := filepath.Abs(mount.Source)
if err != nil {
- return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
+ return nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
}
mount.Source = absSrc
}
@@ -140,7 +174,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
finalVolumes = append(finalVolumes, volume)
}
- return finalMounts, finalVolumes, nil
+ finalOverlays := make([]*specgen.OverlayVolume, 0, len(unifiedOverlays))
+ for _, volume := range unifiedOverlays {
+ finalOverlays = append(finalOverlays, volume)
+ }
+
+ return finalMounts, finalVolumes, finalOverlays, nil
}
// Get image volumes from the given image
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index 90c56d366..d15745fa0 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -27,19 +27,25 @@ const (
// Private indicates the namespace is private
Private NamespaceMode = "private"
// NoNetwork indicates no network namespace should
- // be joined. loopback should still exists
+ // be joined. loopback should still exists.
+ // Only used with the network namespace, invalid otherwise.
NoNetwork NamespaceMode = "none"
// Bridge indicates that a CNI network stack
- // should be used
+ // should be used.
+ // Only used with the network namespace, invalid otherwise.
Bridge NamespaceMode = "bridge"
// Slirp indicates that a slirp4netns network stack should
- // be used
+ // be used.
+ // Only used with the network namespace, invalid otherwise.
Slirp NamespaceMode = "slirp4netns"
// KeepId indicates a user namespace to keep the owner uid inside
- // of the namespace itself
+ // of the namespace itself.
+ // Only used with the user namespace, invalid otherwise.
KeepID NamespaceMode = "keep-id"
- // KeepId indicates to automatically create a user namespace
+ // Auto indicates to automatically create a user namespace.
+ // Only used with the user namespace, invalid otherwise.
Auto NamespaceMode = "auto"
+
// DefaultKernelNamespaces is a comma-separated list of default kernel
// namespaces.
DefaultKernelNamespaces = "cgroup,ipc,net,uts"
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 0a9a16ea7..fad2406e5 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -1,13 +1,13 @@
package specgen
import (
- "errors"
"net"
"syscall"
"github.com/containers/image/v5/manifest"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
)
// LogConfig describes the logging characteristics for a container
@@ -459,42 +459,6 @@ type SpecGenerator struct {
ContainerHealthCheckConfig
}
-// NamedVolume holds information about a named volume that will be mounted into
-// the container.
-type NamedVolume struct {
- // Name is the name of the named volume to be mounted. May be empty.
- // If empty, a new named volume with a pseudorandomly generated name
- // will be mounted at the given destination.
- Name string
- // Destination to mount the named volume within the container. Must be
- // an absolute path. Path will be created if it does not exist.
- Dest string
- // Options are options that the named volume will be mounted with.
- Options []string
-}
-
-// OverlayVolume holds information about a overlay volume that will be mounted into
-// the container.
-type OverlayVolume struct {
- // Destination is the absolute path where the mount will be placed in the container.
- Destination string `json:"destination"`
- // Source specifies the source path of the mount.
- Source string `json:"source,omitempty"`
-}
-
-// ImageVolume is a volume based on a container image. The container image is
-// first mounted on the host and is then bind-mounted into the container. An
-// ImageVolume is always mounted read only.
-type ImageVolume struct {
- // Source is the source of the image volume. The image can be referred
- // to by name and by ID.
- Source string
- // Destination is the absolute path of the mount in the container.
- Destination string
- // ReadWrite sets the volume writable.
- ReadWrite bool
-}
-
// PortMapping is one or more ports that will be mapped into the container.
type PortMapping struct {
// HostIP is the IP that we will bind to on the host.
diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go
new file mode 100644
index 000000000..a4f42d715
--- /dev/null
+++ b/pkg/specgen/volumes.go
@@ -0,0 +1,149 @@
+package specgen
+
+import (
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/buildah/pkg/parse"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// NamedVolume holds information about a named volume that will be mounted into
+// the container.
+type NamedVolume struct {
+ // Name is the name of the named volume to be mounted. May be empty.
+ // If empty, a new named volume with a pseudorandomly generated name
+ // will be mounted at the given destination.
+ Name string
+ // Destination to mount the named volume within the container. Must be
+ // an absolute path. Path will be created if it does not exist.
+ Dest string
+ // Options are options that the named volume will be mounted with.
+ Options []string
+}
+
+// OverlayVolume holds information about a overlay volume that will be mounted into
+// the container.
+type OverlayVolume struct {
+ // Destination is the absolute path where the mount will be placed in the container.
+ Destination string `json:"destination"`
+ // Source specifies the source path of the mount.
+ Source string `json:"source,omitempty"`
+}
+
+// ImageVolume is a volume based on a container image. The container image is
+// first mounted on the host and is then bind-mounted into the container. An
+// ImageVolume is always mounted read only.
+type ImageVolume struct {
+ // Source is the source of the image volume. The image can be referred
+ // to by name and by ID.
+ Source string
+ // Destination is the absolute path of the mount in the container.
+ Destination string
+ // ReadWrite sets the volume writable.
+ ReadWrite bool
+}
+
+// GenVolumeMounts parses user input into mounts, volumes and overlay volumes
+func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*NamedVolume, map[string]*OverlayVolume, error) {
+ errDuplicateDest := errors.Errorf("duplicate mount destination")
+
+ mounts := make(map[string]spec.Mount)
+ volumes := make(map[string]*NamedVolume)
+ overlayVolumes := make(map[string]*OverlayVolume)
+
+ volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
+
+ for _, vol := range volumeFlag {
+ var (
+ options []string
+ src string
+ dest string
+ err error
+ )
+
+ splitVol := strings.Split(vol, ":")
+ if len(splitVol) > 3 {
+ return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol)
+ }
+
+ src = splitVol[0]
+ if len(splitVol) == 1 {
+ // This is an anonymous named volume. Only thing given
+ // is destination.
+ // Name/source will be blank, and populated by libpod.
+ src = ""
+ dest = splitVol[0]
+ } else if len(splitVol) > 1 {
+ dest = splitVol[1]
+ }
+ if len(splitVol) > 2 {
+ if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
+ return nil, nil, nil, err
+ }
+ }
+
+ // Do not check source dir for anonymous volumes
+ if len(splitVol) > 1 {
+ if len(src) == 0 {
+ return nil, nil, nil, errors.New("host directory cannot be empty")
+ }
+ }
+ if err := parse.ValidateVolumeCtrDir(dest); err != nil {
+ return nil, nil, nil, err
+ }
+
+ cleanDest := filepath.Clean(dest)
+
+ if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
+ // This is not a named volume
+ overlayFlag := false
+ for _, o := range options {
+ if o == "O" {
+ overlayFlag = true
+ if len(options) > 1 {
+ return nil, nil, nil, errors.New("can't use 'O' with other options")
+ }
+ }
+ }
+ if overlayFlag {
+ // This is a overlay volume
+ newOverlayVol := new(OverlayVolume)
+ newOverlayVol.Destination = cleanDest
+ newOverlayVol.Source = src
+ if _, ok := overlayVolumes[newOverlayVol.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination)
+ }
+ overlayVolumes[newOverlayVol.Destination] = newOverlayVol
+ } else {
+ newMount := spec.Mount{
+ Destination: cleanDest,
+ Type: "bind",
+ Source: src,
+ Options: options,
+ }
+ if _, ok := mounts[newMount.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination)
+ }
+ mounts[newMount.Destination] = newMount
+ }
+ } else {
+ // This is a named volume
+ newNamedVol := new(NamedVolume)
+ newNamedVol.Name = src
+ newNamedVol.Dest = cleanDest
+ newNamedVol.Options = options
+
+ if _, ok := volumes[newNamedVol.Dest]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest)
+ }
+ volumes[newNamedVol.Dest] = newNamedVol
+ }
+
+ logrus.Debugf("User mount %s:%s options %v", src, dest, options)
+ }
+
+ return mounts, volumes, overlayVolumes, nil
+}
diff --git a/pkg/varlink/generate.go b/pkg/varlink/generate.go
deleted file mode 100644
index b3f58d4a5..000000000
--- a/pkg/varlink/generate.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package iopodman
-
-//go:generate go run ../../vendor/github.com/varlink/go/cmd/varlink-go-interface-generator/main.go io.podman.varlink
diff --git a/pkg/varlink/io.podman.varlink b/pkg/varlink/io.podman.varlink
deleted file mode 100644
index cd6316011..000000000
--- a/pkg/varlink/io.podman.varlink
+++ /dev/null
@@ -1,1398 +0,0 @@
-# Podman Service Interface and API description. The master version of this document can be found
-# in the [API.md](https://github.com/containers/podman/blob/master/API.md) file in the upstream libpod repository.
-interface io.podman
-
-type Volume (
- name: string,
- labels: [string]string,
- mountPoint: string,
- driver: string,
- options: [string]string
-)
-
-type NotImplemented (
- comment: string
-)
-
-type StringResponse (
- message: string
-)
-
-type RemoveImageResponse (
- untagged: []string,
- deleted: string
-)
-
-type LogLine (
- device: string,
- parseLogType : string,
- time: string,
- msg: string,
- cid: string
-)
-
-# ContainerChanges describes the return struct for ListContainerChanges
-type ContainerChanges (
- changed: []string,
- added: []string,
- deleted: []string
-)
-
-type ImageSaveOptions (
- name: string,
- format: string,
- output: string,
- outputType: string,
- moreTags: []string,
- quiet: bool,
- compress: bool
-)
-
-type VolumeCreateOpts (
- volumeName: string,
- driver: string,
- labels: [string]string,
- options: [string]string
-)
-
-type VolumeRemoveOpts (
- volumes: []string,
- all: bool,
- force: bool
-)
-
-type Image (
- id: string,
- digest: string,
- digests: []string,
- parentId: string,
- repoTags: []string,
- repoDigests: []string,
- created: string, # as RFC3339
- size: int,
- virtualSize: int,
- containers: int,
- labels: [string]string,
- isParent: bool,
- topLayer: string,
- readOnly: bool,
- history: []string
-)
-
-# ImageHistory describes the returned structure from ImageHistory.
-type ImageHistory (
- id: string,
- created: string, # as RFC3339
- createdBy: string,
- tags: []string,
- size: int,
- comment: string
-)
-
-# Represents a single search result from SearchImages
-type ImageSearchResult (
- description: string,
- is_official: bool,
- is_automated: bool,
- registry: string,
- name: string,
- star_count: int
-)
-
-type ImageSearchFilter (
- is_official: ?bool,
- is_automated: ?bool,
- star_count: int
-)
-
-type AuthConfig (
- username: string,
- password: string
-)
-
-type KubePodService (
- pod: string,
- service: string
-)
-
-type Container (
- id: string,
- image: string,
- imageid: string,
- command: []string,
- createdat: string, # as RFC3339
- runningfor: string,
- status: string,
- ports: []ContainerPortMappings,
- rootfssize: int,
- rwsize: int,
- names: string,
- labels: [string]string,
- mounts: []ContainerMount,
- containerrunning: bool,
- namespaces: ContainerNameSpace
-)
-
-# ContainerStats is the return struct for the stats of a container
-type ContainerStats (
- id: string,
- name: string,
- cpu: float,
- cpu_nano: int,
- system_nano: int,
- mem_usage: int,
- mem_limit: int,
- mem_perc: float,
- net_input: int,
- net_output: int,
- block_output: int,
- block_input: int,
- pids: int
-)
-
-type PsOpts (
- all: bool,
- filters: ?[]string,
- last: ?int,
- latest: ?bool,
- noTrunc: ?bool,
- pod: ?bool,
- quiet: ?bool,
- size: ?bool,
- sort: ?string,
- sync: ?bool
-)
-
-type PsContainer (
- id: string,
- image: string,
- command: string,
- created: string,
- ports: string,
- names: string,
- isInfra: bool,
- status: string,
- state: string,
- pidNum: int,
- rootFsSize: int,
- rwSize: int,
- pod: string,
- createdAt: string,
- exitedAt: string,
- startedAt: string,
- labels: [string]string,
- nsPid: string,
- cgroup: string,
- ipc: string,
- mnt: string,
- net: string,
- pidNs: string,
- user: string,
- uts: string,
- mounts: string
-)
-
-# ContainerMount describes the struct for mounts in a container
-type ContainerMount (
- destination: string,
- type: string,
- source: string,
- options: []string
-)
-
-# ContainerPortMappings describes the struct for portmappings in an existing container
-type ContainerPortMappings (
- host_port: string,
- host_ip: string,
- protocol: string,
- container_port: string
-)
-
-# ContainerNamespace describes the namespace structure for an existing container
-type ContainerNameSpace (
- user: string,
- uts: string,
- pidns: string,
- pid: string,
- cgroup: string,
- net: string,
- mnt: string,
- ipc: string
-)
-
-# InfoDistribution describes the host's distribution
-type InfoDistribution (
- distribution: string,
- version: string
-)
-
-# InfoHost describes the host stats portion of PodmanInfo
-type InfoHost (
- buildah_version: string,
- distribution: InfoDistribution,
- mem_free: int,
- mem_total: int,
- swap_free: int,
- swap_total: int,
- arch: string,
- cpus: int,
- hostname: string,
- kernel: string,
- os: string,
- uptime: string,
- eventlogger: string
-)
-
-# InfoGraphStatus describes the detailed status of the storage driver
-type InfoGraphStatus (
- backing_filesystem: string,
- native_overlay_diff: string,
- supports_d_type: string
-)
-
-# InfoRegistry describes the host's registry information
-type InfoRegistry (
- search: []string,
- insecure: []string,
- blocked: []string
-)
-
-# InfoStore describes the host's storage information
-type InfoStore (
- containers: int,
- images: int,
- graph_driver_name: string,
- graph_driver_options: string,
- graph_root: string,
- graph_status: InfoGraphStatus,
- run_root: string
-)
-
-# InfoPodman provides details on the Podman binary
-type InfoPodmanBinary (
- compiler: string,
- go_version: string,
- podman_version: string,
- git_commit: string
-)
-
-# PodmanInfo describes the Podman host and build
-type PodmanInfo (
- host: InfoHost,
- registries: InfoRegistry,
- store: InfoStore,
- podman: InfoPodmanBinary
-)
-
-# Sockets describes sockets location for a container
-type Sockets(
- container_id: string,
- io_socket: string,
- control_socket: string
-)
-
-# Create is an input structure for creating containers.
-# args[0] is the image name or id
-# args[1-] are the new commands if changed
-type Create (
- args: []string,
- addHost: ?[]string,
- annotation: ?[]string,
- attach: ?[]string,
- blkioWeight: ?string,
- blkioWeightDevice: ?[]string,
- capAdd: ?[]string,
- capDrop: ?[]string,
- cgroupParent: ?string,
- cidFile: ?string,
- conmonPidfile: ?string,
- command: ?[]string,
- cpuPeriod: ?int,
- cpuQuota: ?int,
- cpuRtPeriod: ?int,
- cpuRtRuntime: ?int,
- cpuShares: ?int,
- cpus: ?float,
- cpuSetCpus: ?string,
- cpuSetMems: ?string,
- detach: ?bool,
- detachKeys: ?string,
- device: ?[]string,
- deviceReadBps: ?[]string,
- deviceReadIops: ?[]string,
- deviceWriteBps: ?[]string,
- deviceWriteIops: ?[]string,
- dns: ?[]string,
- dnsOpt: ?[]string,
- dnsSearch: ?[]string,
- dnsServers: ?[]string,
- entrypoint: ?string,
- env: ?[]string,
- envFile: ?[]string,
- expose: ?[]string,
- gidmap: ?[]string,
- groupadd: ?[]string,
- healthcheckCommand: ?string,
- healthcheckInterval: ?string,
- healthcheckRetries: ?int,
- healthcheckStartPeriod: ?string,
- healthcheckTimeout:?string,
- hostname: ?string,
- imageVolume: ?string,
- init: ?bool,
- initPath: ?string,
- interactive: ?bool,
- ip: ?string,
- ipc: ?string,
- kernelMemory: ?string,
- label: ?[]string,
- labelFile: ?[]string,
- logDriver: ?string,
- logOpt: ?[]string,
- macAddress: ?string,
- memory: ?string,
- memoryReservation: ?string,
- memorySwap: ?string,
- memorySwappiness: ?int,
- name: ?string,
- network: ?string,
- noHosts: ?bool,
- oomKillDisable: ?bool,
- oomScoreAdj: ?int,
- overrideArch: ?string,
- overrideOS: ?string,
- pid: ?string,
- pidsLimit: ?int,
- pod: ?string,
- privileged: ?bool,
- publish: ?[]string,
- publishAll: ?bool,
- pull: ?string,
- quiet: ?bool,
- readonly: ?bool,
- readonlytmpfs: ?bool,
- restart: ?string,
- rm: ?bool,
- rootfs: ?bool,
- securityOpt: ?[]string,
- shmSize: ?string,
- stopSignal: ?string,
- stopTimeout: ?int,
- storageOpt: ?[]string,
- subuidname: ?string,
- subgidname: ?string,
- sysctl: ?[]string,
- systemd: ?string,
- tmpfs: ?[]string,
- tty: ?bool,
- uidmap: ?[]string,
- ulimit: ?[]string,
- user: ?string,
- userns: ?string,
- uts: ?string,
- mount: ?[]string,
- volume: ?[]string,
- volumesFrom: ?[]string,
- workDir: ?string
-)
-
-# BuildOptions are are used to describe describe physical attributes of the build
-type BuildOptions (
- addHosts: []string,
- cgroupParent: string,
- cpuPeriod: int,
- cpuQuota: int,
- cpuShares: int,
- cpusetCpus: string,
- cpusetMems: string,
- memory: int,
- memorySwap: int,
- shmSize: string,
- ulimit: []string,
- volume: []string
-)
-
-# BuildInfo is used to describe user input for building images
-type BuildInfo (
- architecture: string,
- addCapabilities: []string,
- additionalTags: []string,
- annotations: []string,
- buildArgs: [string]string,
- buildOptions: BuildOptions,
- cniConfigDir: string,
- cniPluginDir: string,
- compression: string,
- contextDir: string,
- defaultsMountFilePath: string,
- devices: []string,
- dockerfiles: []string,
- dropCapabilities: []string,
- err: string,
- forceRmIntermediateCtrs: bool,
- iidfile: string,
- label: []string,
- layers: bool,
- nocache: bool,
- os: string,
- out: string,
- output: string,
- outputFormat: string,
- pullPolicy: string,
- quiet: bool,
- remoteIntermediateCtrs: bool,
- reportWriter: string,
- runtimeArgs: []string,
- signBy: string,
- squash: bool,
- target: string,
- transientMounts: []string
-)
-
-# MoreResponse is a struct for when responses from varlink requires longer output
-type MoreResponse (
- logs: []string,
- id: string
-)
-
-# ListPodContainerInfo is a returned struct for describing containers
-# in a pod.
-type ListPodContainerInfo (
- name: string,
- id: string,
- status: string
-)
-
-# PodCreate is an input structure for creating pods.
-# It emulates options to podman pod create. The infraCommand and
-# infraImage options are currently NotSupported.
-type PodCreate (
- name: string,
- cgroupParent: string,
- labels: [string]string,
- share: []string,
- infra: bool,
- infraCommand: string,
- infraImage: string,
- publish: []string
-)
-
-# ListPodData is the returned struct for an individual pod
-type ListPodData (
- id: string,
- name: string,
- createdat: string,
- cgroup: string,
- status: string,
- labels: [string]string,
- numberofcontainers: string,
- containersinfo: []ListPodContainerInfo
-)
-
-type PodContainerErrorData (
- containerid: string,
- reason: string
-)
-
-# Runlabel describes the required input for container runlabel
-type Runlabel(
- image: string,
- authfile: string,
- display: bool,
- name: string,
- pull: bool,
- label: string,
- extraArgs: []string,
- opts: [string]string
-)
-
-# Event describes a libpod struct
-type Event(
- # TODO: make status and type a enum at some point?
- # id is the container, volume, pod, image ID
- id: string,
- # image is the image name where applicable
- image: string,
- # name is the name of the pod, container, image
- name: string,
- # status describes the event that happened (i.e. create, remove, ...)
- status: string,
- # time the event happened
- time: string,
- # type describes object the event happened with (image, container...)
- type: string
-)
-
-type DiffInfo(
- # path that is different
- path: string,
- # Add, Delete, Modify
- changeType: string
-)
-
-type ExecOpts(
- # container name or id
- name: string,
- # Create pseudo tty
- tty: bool,
- # privileged access in container
- privileged: bool,
- # command to execute in container
- cmd: []string,
- # user to use in container
- user: ?string,
- # workdir to run command in container
- workdir: ?string,
- # slice of keyword=value environment variables
- env: ?[]string,
- # string of detach keys
- detachKeys: ?string
-)
-
-# GetVersion returns version and build information of the podman service
-method GetVersion() -> (
- version: string,
- go_version: string,
- git_commit: string,
- built: string, # as RFC3339
- os_arch: string,
- remote_api_version: int
-)
-
-# Reset resets Podman back to its initial state.
-# Removes all Pods, Containers, Images and Volumes
-method Reset() -> ()
-
-# GetInfo returns a [PodmanInfo](#PodmanInfo) struct that describes podman and its host such as storage stats,
-# build information of Podman, and system-wide registries.
-method GetInfo() -> (info: PodmanInfo)
-
-# ListContainers returns information about all containers.
-# See also [GetContainer](#GetContainer).
-method ListContainers() -> (containers: []Container)
-
-method Ps(opts: PsOpts) -> (containers: []PsContainer)
-
-method GetContainersByStatus(status: []string) -> (containerS: []Container)
-
-method Top (nameOrID: string, descriptors: []string) -> (top: []string)
-
-# HealthCheckRun executes defined container's healthcheck command
-# and returns the container's health status.
-method HealthCheckRun (nameOrID: string) -> (healthCheckStatus: string)
-
-# GetContainer returns information about a single container. If a container
-# with the given id doesn't exist, a [ContainerNotFound](#ContainerNotFound)
-# error will be returned. See also [ListContainers](ListContainers) and
-# [InspectContainer](#InspectContainer).
-method GetContainer(id: string) -> (container: Container)
-
-# GetContainersByContext allows you to get a list of container ids depending on all, latest, or a list of
-# container names. The definition of latest container means the latest by creation date. In a multi-
-# user environment, results might differ from what you expect.
-method GetContainersByContext(all: bool, latest: bool, args: []string) -> (containers: []string)
-
-# CreateContainer creates a new container from an image. It uses a [Create](#Create) type for input.
-method CreateContainer(create: Create) -> (container: string)
-
-# InspectContainer data takes a name or ID of a container returns the inspection
-# data in string format. You can then serialize the string into JSON. A [ContainerNotFound](#ContainerNotFound)
-# error will be returned if the container cannot be found. See also [InspectImage](#InspectImage).
-method InspectContainer(name: string) -> (container: string)
-
-# ListContainerProcesses takes a name or ID of a container and returns the processes
-# running inside the container as array of strings. It will accept an array of string
-# arguments that represent ps options. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound)
-# error will be returned.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerProcesses '{"name": "135d71b9495f", "opts": []}'
-# {
-# "container": [
-# " UID PID PPID C STIME TTY TIME CMD",
-# " 0 21220 21210 0 09:05 pts/0 00:00:00 /bin/sh",
-# " 0 21232 21220 0 09:05 pts/0 00:00:00 top",
-# " 0 21284 21220 0 09:05 pts/0 00:00:00 vi /etc/hosts"
-# ]
-# }
-# ~~~
-method ListContainerProcesses(name: string, opts: []string) -> (container: []string)
-
-# GetContainerLogs takes a name or ID of a container and returns the logs of that container.
-# If the container cannot be found, a [ContainerNotFound](#ContainerNotFound) error will be returned.
-# The container logs are returned as an array of strings. GetContainerLogs will honor the streaming
-# capability of varlink if the client invokes it.
-method GetContainerLogs(name: string) -> (container: []string)
-
-method GetContainersLogs(names: []string, follow: bool, latest: bool, since: string, tail: int, timestamps: bool) -> (log: LogLine)
-
-# ListContainerChanges takes a name or ID of a container and returns changes between the container and
-# its base image. It returns a struct of changed, deleted, and added path names.
-method ListContainerChanges(name: string) -> (container: ContainerChanges)
-
-# ExportContainer creates an image from a container. It takes the name or ID of a container and a
-# path representing the target tarfile. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound)
-# error will be returned.
-# The return value is the written tarfile.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ExportContainer '{"name": "flamboyant_payne", "path": "/tmp/payne.tar" }'
-# {
-# "tarfile": "/tmp/payne.tar"
-# }
-# ~~~
-method ExportContainer(name: string, path: string) -> (tarfile: string)
-
-# GetContainerStats takes the name or ID of a container and returns a single ContainerStats structure which
-# contains attributes like memory and cpu usage. If the container cannot be found, a
-# [ContainerNotFound](#ContainerNotFound) error will be returned. If the container is not running, a [NoContainerRunning](#NoContainerRunning)
-# error will be returned
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.GetContainerStats '{"name": "c33e4164f384"}'
-# {
-# "container": {
-# "block_input": 0,
-# "block_output": 0,
-# "cpu": 2.571123918839990154678e-08,
-# "cpu_nano": 49037378,
-# "id": "c33e4164f384aa9d979072a63319d66b74fd7a128be71fa68ede24f33ec6cfee",
-# "mem_limit": 33080606720,
-# "mem_perc": 2.166828456524753747370e-03,
-# "mem_usage": 716800,
-# "name": "competent_wozniak",
-# "net_input": 768,
-# "net_output": 5910,
-# "pids": 1,
-# "system_nano": 10000000
-# }
-# }
-# ~~~
-method GetContainerStats(name: string) -> (container: ContainerStats)
-
-# GetContainerStatsWithHistory takes a previous set of container statistics and uses libpod functions
-# to calculate the containers statistics based on current and previous measurements.
-method GetContainerStatsWithHistory(previousStats: ContainerStats) -> (container: ContainerStats)
-
-# This method has not be implemented yet.
-# method ResizeContainerTty() -> (notimplemented: NotImplemented)
-
-# StartContainer starts a created or stopped container. It takes the name or ID of container. It returns
-# the container ID once started. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound)
-# error will be returned. See also [CreateContainer](#CreateContainer).
-method StartContainer(name: string) -> (container: string)
-
-# StopContainer stops a container given a timeout. It takes the name or ID of a container as well as a
-# timeout value. The timeout value the time before a forcible stop to the container is applied. It
-# returns the container ID once stopped. If the container cannot be found, a [ContainerNotFound](#ContainerNotFound)
-# error will be returned instead. See also [KillContainer](KillContainer).
-# #### Error
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.StopContainer '{"name": "135d71b9495f", "timeout": 5}'
-# {
-# "container": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6"
-# }
-# ~~~
-method StopContainer(name: string, timeout: int) -> (container: string)
-
-# InitContainer initializes the given container. It accepts a container name or
-# ID, and will initialize the container matching that ID if possible, and error
-# if not. Containers can only be initialized when they are in the Created or
-# Exited states. Initialization prepares a container to be started, but does not
-# start the container. It is intended to be used to debug a container's state
-# prior to starting it.
-method InitContainer(name: string) -> (container: string)
-
-# RestartContainer will restart a running container given a container name or ID and timeout value. The timeout
-# value is the time before a forcible stop is used to stop the container. If the container cannot be found by
-# name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise, the ID of the
-# container will be returned.
-method RestartContainer(name: string, timeout: int) -> (container: string)
-
-# KillContainer takes the name or ID of a container as well as a signal to be applied to the container. Once the
-# container has been killed, the container's ID is returned. If the container cannot be found, a
-# [ContainerNotFound](#ContainerNotFound) error is returned. See also [StopContainer](StopContainer).
-method KillContainer(name: string, signal: int) -> (container: string)
-
-# This method has not be implemented yet.
-# method UpdateContainer() -> (notimplemented: NotImplemented)
-
-# This method has not be implemented yet.
-# method RenameContainer() -> (notimplemented: NotImplemented)
-
-# PauseContainer takes the name or ID of container and pauses it. If the container cannot be found,
-# a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned.
-# See also [UnpauseContainer](#UnpauseContainer).
-method PauseContainer(name: string) -> (container: string)
-
-# UnpauseContainer takes the name or ID of container and unpauses a paused container. If the container cannot be
-# found, a [ContainerNotFound](#ContainerNotFound) error will be returned; otherwise the ID of the container is returned.
-# See also [PauseContainer](#PauseContainer).
-method UnpauseContainer(name: string) -> (container: string)
-
-# Attach takes the name or ID of a container and sets up the ability to remotely attach to its console. The start
-# bool is whether you wish to start the container in question first.
-method Attach(name: string, detachKeys: string, start: bool) -> ()
-
-method AttachControl(name: string) -> ()
-
-# GetAttachSockets takes the name or ID of an existing container. It returns file paths for two sockets needed
-# to properly communicate with a container. The first is the actual I/O socket that the container uses. The
-# second is a "control" socket where things like resizing the TTY events are sent. If the container cannot be
-# found, a [ContainerNotFound](#ContainerNotFound) error will be returned.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/io.podman/io.podman.GetAttachSockets '{"name": "b7624e775431219161"}'
-# {
-# "sockets": {
-# "container_id": "b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca",
-# "control_socket": "/var/lib/containers/storage/overlay-containers/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/userdata/ctl",
-# "io_socket": "/var/run/libpod/socket/b7624e7754312191613245ce1a46844abee60025818fe3c3f3203435623a1eca/attach"
-# }
-# }
-# ~~~
-method GetAttachSockets(name: string) -> (sockets: Sockets)
-
-# WaitContainer takes the name or ID of a container and waits the given interval in milliseconds until the container
-# stops. Upon stopping, the return code of the container is returned. If the container container cannot be found by ID
-# or name, a [ContainerNotFound](#ContainerNotFound) error is returned.
-method WaitContainer(name: string, interval: int) -> (exitcode: int)
-
-# RemoveContainer requires the name or ID of a container as well as a boolean that
-# indicates whether a container should be forcefully removed (e.g., by stopping it), and a boolean
-# indicating whether to remove builtin volumes. Upon successful removal of the
-# container, its ID is returned. If the
-# container cannot be found by name or ID, a [ContainerNotFound](#ContainerNotFound) error will be returned.
-# See also [EvictContainer](EvictContainer).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.RemoveContainer '{"name": "62f4fd98cb57"}'
-# {
-# "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20"
-# }
-# ~~~
-method RemoveContainer(name: string, force: bool, removeVolumes: bool) -> (container: string)
-
-# EvictContainer requires the name or ID of a container as well as a boolean that
-# indicates to remove builtin volumes. Upon successful eviction of the container,
-# its ID is returned. If the container cannot be found by name or ID,
-# a [ContainerNotFound](#ContainerNotFound) error will be returned.
-# See also [RemoveContainer](RemoveContainer).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.EvictContainer '{"name": "62f4fd98cb57"}'
-# {
-# "container": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20"
-# }
-# ~~~
-method EvictContainer(name: string, removeVolumes: bool) -> (container: string)
-
-# DeleteStoppedContainers will delete all containers that are not running. It will return a list the deleted
-# container IDs. See also [RemoveContainer](RemoveContainer).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.DeleteStoppedContainers
-# {
-# "containers": [
-# "451410b931d00def8aa9b4f8084e4d4a39e5e04ea61f358cf53a5cf95afcdcee",
-# "8b60f754a3e01389494a9581ade97d35c2765b6e2f19acd2d3040c82a32d1bc0",
-# "cf2e99d4d3cad6073df199ed32bbe64b124f3e1aba6d78821aa8460e70d30084",
-# "db901a329587312366e5ecff583d08f0875b4b79294322df67d90fc6eed08fc1"
-# ]
-# }
-# ~~~
-method DeleteStoppedContainers() -> (containers: []string)
-
-# ListImages returns information about the images that are currently in storage.
-# See also [InspectImage](#InspectImage).
-method ListImages() -> (images: []Image)
-
-# ListImagesWithFilters returns information about the images that are currently in storage
-# after one or more filters has been applied.
-# See also [InspectImage](#InspectImage).
-method ListImagesWithFilters(filters: []string) -> (images: []Image)
-
-# GetImage returns information about a single image in storage.
-# If the image caGetImage returns be found, [ImageNotFound](#ImageNotFound) will be returned.
-method GetImage(id: string) -> (image: Image)
-
-# BuildImage takes a [BuildInfo](#BuildInfo) structure and builds an image. At a minimum, you must provide the
-# contextDir tarball path, the 'dockerfiles' path, and 'output' option in the BuildInfo structure. The 'output'
-# options is the name of the of the resulting build. It will return a [MoreResponse](#MoreResponse) structure
-# that contains the build logs and resulting image ID.
-# #### Example
-# ~~~
-# $ sudo varlink call -m unix:///run/podman/io.podman/io.podman.BuildImage '{"build":{"contextDir":"/tmp/t/context.tar","dockerfiles":["Dockerfile"], "output":"foobar"}}'
-# {
-# "image": {
-# "id": "",
-# "logs": [
-# "STEP 1: FROM alpine\n"
-# ]
-# }
-# }
-# {
-# "image": {
-# "id": "",
-# "logs": [
-# "STEP 2: COMMIT foobar\n"
-# ]
-# }
-# }
-# {
-# "image": {
-# "id": "",
-# "logs": [
-# "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9\n"
-# ]
-# }
-# }
-# {
-# "image": {
-# "id": "b7b28af77ffec6054d13378df4fdf02725830086c7444d9c278af25312aa39b9",
-# "logs": []
-# }
-# }
-# ~~~
-method BuildImage(build: BuildInfo) -> (image: MoreResponse)
-
-# This function is not implemented yet.
-# method CreateImage() -> (notimplemented: NotImplemented)
-
-# InspectImage takes the name or ID of an image and returns a string representation of data associated with the
-#image. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will
-# be returned if the image cannot be found.
-method InspectImage(name: string) -> (image: string)
-
-# HistoryImage takes the name or ID of an image and returns information about its history and layers. The returned
-# history is in the form of an array of ImageHistory structures. If the image cannot be found, an
-# [ImageNotFound](#ImageNotFound) error is returned.
-method HistoryImage(name: string) -> (history: []ImageHistory)
-
-# PushImage takes two input arguments: the name or ID of an image, the fully-qualified destination name of the image,
-# It will return an [ImageNotFound](#ImageNotFound) error if
-# the image cannot be found in local storage; otherwise it will return a [MoreResponse](#MoreResponse)
-method PushImage(name: string, tag: string, compress: bool, format: string, removeSignatures: bool, signBy: string) -> (reply: MoreResponse)
-
-# TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot
-# be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success.
-method TagImage(name: string, tagged: string) -> (image: string)
-
-# UntagImage takes the name or ID of an image in local storage as well as the
-# tag name to be removed. If the image cannot be found, an
-# [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of
-# the image is returned on success.
-method UntagImage(name: string, tag: string) -> (image: string)
-
-# RemoveImage takes the name or ID of an image as well as a boolean that determines if containers using that image
-# should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The
-# ID of the removed image is returned when complete. See also [DeleteUnusedImages](DeleteUnusedImages).
-# #### Example
-# ~~~
-# varlink call -m unix:/run/podman/io.podman/io.podman.RemoveImage '{"name": "registry.fedoraproject.org/fedora", "force": true}'
-# {
-# "image": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e"
-# }
-# ~~~
-method RemoveImage(name: string, force: bool) -> (image: string)
-
-# RemoveImageWithResponse takes the name or ID of an image as well as a boolean that determines if containers using that image
-# should be deleted. If the image cannot be found, an [ImageNotFound](#ImageNotFound) error will be returned. The response is
-# in the form of a RemoveImageResponse .
-method RemoveImageWithResponse(name: string, force: bool) -> (response: RemoveImageResponse)
-
-# SearchImages searches available registries for images that contain the
-# contents of "query" in their name. If "limit" is given, limits the amount of
-# search results per registry.
-method SearchImages(query: string, limit: ?int, filter: ImageSearchFilter) -> (results: []ImageSearchResult)
-
-# DeleteUnusedImages deletes any images not associated with a container. The IDs of the deleted images are returned
-# in a string array.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.DeleteUnusedImages
-# {
-# "images": [
-# "166ea6588079559c724c15223f52927f514f73dd5c5cf2ae2d143e3b2e6e9b52",
-# "da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e",
-# "3ef70f7291f47dfe2b82931a993e16f5a44a0e7a68034c3e0e086d77f5829adc",
-# "59788edf1f3e78cd0ebe6ce1446e9d10788225db3dedcfd1a59f764bad2b2690"
-# ]
-# }
-# ~~~
-method DeleteUnusedImages() -> (images: []string)
-
-# Commit, creates an image from an existing container. It requires the name or
-# ID of the container as well as the resulting image name. Optionally, you can define an author and message
-# to be added to the resulting image. You can also define changes to the resulting image for the following
-# attributes: _CMD, ENTRYPOINT, ENV, EXPOSE, LABEL, ONBUILD, STOPSIGNAL, USER, VOLUME, and WORKDIR_. To pause the
-# container while it is being committed, pass a _true_ bool for the pause argument. If the container cannot
-# be found by the ID or name provided, a (ContainerNotFound)[#ContainerNotFound] error will be returned; otherwise,
-# the resulting image's ID will be returned as a string inside a MoreResponse.
-method Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) -> (reply: MoreResponse)
-
-# ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
-# descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
-method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string)
-
-# ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also
-# a boolean option to force compression. It also takes in a string array of tags to be able to save multiple
-# tags of the same image to a tarball (each tag should be of the form <image>:<tag>). Upon completion, the ID
-# of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound)
-# error will be returned. See also [ImportImage](ImportImage).
-method ExportImage(name: string, destination: string, compress: bool, tags: []string) -> (image: string)
-
-# PullImage pulls an image from a repository to local storage. After a successful pull, the image id and logs
-# are returned as a [MoreResponse](#MoreResponse). This connection also will handle a WantsMores request to send
-# status as it occurs.
-method PullImage(name: string, creds: AuthConfig) -> (reply: MoreResponse)
-
-# CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input.
-# On success, the ID of the newly created pod will be returned.
-# #### Example
-# ~~~
-# $ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"name": "test"}}'
-# {
-# "pod": "b05dee7bd4ccfee688099fe1588a7a898d6ddd6897de9251d4671c9b0feacb2a"
-# }
-#
-# $ varlink call unix:/run/podman/io.podman/io.podman.CreatePod '{"create": {"infra": true, "share": ["ipc", "net", "uts"]}}'
-# {
-# "pod": "d7697449a8035f613c1a8891286502aca68fff7d5d49a85279b3bda229af3b28"
-# }
-# ~~~
-method CreatePod(create: PodCreate) -> (pod: string)
-
-# ListPods returns a list of pods in no particular order. They are
-# returned as an array of ListPodData structs. See also [GetPod](#GetPod).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ListPods
-# {
-# "pods": [
-# {
-# "cgroup": "machine.slice",
-# "containersinfo": [
-# {
-# "id": "00c130a45de0411f109f1a0cfea2e298df71db20fa939de5cab8b2160a36be45",
-# "name": "1840835294cf-infra",
-# "status": "running"
-# },
-# {
-# "id": "49a5cce72093a5ca47c6de86f10ad7bb36391e2d89cef765f807e460865a0ec6",
-# "name": "upbeat_murdock",
-# "status": "running"
-# }
-# ],
-# "createdat": "2018-12-07 13:10:15.014139258 -0600 CST",
-# "id": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f",
-# "name": "foobar",
-# "numberofcontainers": "2",
-# "status": "Running"
-# },
-# {
-# "cgroup": "machine.slice",
-# "containersinfo": [
-# {
-# "id": "1ca4b7bbba14a75ba00072d4b705c77f3df87db0109afaa44d50cb37c04a477e",
-# "name": "784306f655c6-infra",
-# "status": "running"
-# }
-# ],
-# "createdat": "2018-12-07 13:09:57.105112457 -0600 CST",
-# "id": "784306f655c6200aea321dd430ba685e9b2cc1f7d7528a72f3ff74ffb29485a2",
-# "name": "nostalgic_pike",
-# "numberofcontainers": "1",
-# "status": "Running"
-# }
-# ]
-# }
-# ~~~
-method ListPods() -> (pods: []ListPodData)
-
-# GetPod takes a name or ID of a pod and returns single [ListPodData](#ListPodData)
-# structure. A [PodNotFound](#PodNotFound) error will be returned if the pod cannot be found.
-# See also [ListPods](ListPods).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.GetPod '{"name": "foobar"}'
-# {
-# "pod": {
-# "cgroup": "machine.slice",
-# "containersinfo": [
-# {
-# "id": "00c130a45de0411f109f1a0cfea2e298df71db20fa939de5cab8b2160a36be45",
-# "name": "1840835294cf-infra",
-# "status": "running"
-# },
-# {
-# "id": "49a5cce72093a5ca47c6de86f10ad7bb36391e2d89cef765f807e460865a0ec6",
-# "name": "upbeat_murdock",
-# "status": "running"
-# }
-# ],
-# "createdat": "2018-12-07 13:10:15.014139258 -0600 CST",
-# "id": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f",
-# "name": "foobar",
-# "numberofcontainers": "2",
-# "status": "Running"
-# }
-# }
-# ~~~
-method GetPod(name: string) -> (pod: ListPodData)
-
-# InspectPod takes the name or ID of an image and returns a string representation of data associated with the
-# pod. You must serialize the string into JSON to use it further. A [PodNotFound](#PodNotFound) error will
-# be returned if the pod cannot be found.
-method InspectPod(name: string) -> (pod: string)
-
-# StartPod starts containers in a pod. It takes the name or ID of pod. If the pod cannot be found, a [PodNotFound](#PodNotFound)
-# error will be returned. Containers in a pod are started independently. If there is an error starting one container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was started with no errors, the pod ID is returned.
-# See also [CreatePod](#CreatePod).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.StartPod '{"name": "135d71b9495f"}'
-# {
-# "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6",
-# }
-# ~~~
-method StartPod(name: string) -> (pod: string)
-
-# StopPod stops containers in a pod. It takes the name or ID of a pod and a timeout.
-# If the pod cannot be found, a [PodNotFound](#PodNotFound) error will be returned instead.
-# Containers in a pod are stopped independently. If there is an error stopping one container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was stopped with no errors, the pod ID is returned.
-# See also [KillPod](KillPod).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.StopPod '{"name": "135d71b9495f"}'
-# {
-# "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6"
-# }
-# ~~~
-method StopPod(name: string, timeout: int) -> (pod: string)
-
-# RestartPod will restart containers in a pod given a pod name or ID. Containers in
-# the pod that are running will be stopped, then all stopped containers will be run.
-# If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned.
-# Containers in a pod are restarted independently. If there is an error restarting one container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was restarted with no errors, the pod ID is returned.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.RestartPod '{"name": "135d71b9495f"}'
-# {
-# "pod": "135d71b9495f7c3967f536edad57750bfdb569336cd107d8aabab45565ffcfb6"
-# }
-# ~~~
-method RestartPod(name: string) -> (pod: string)
-
-# KillPod takes the name or ID of a pod as well as a signal to be applied to the pod. If the pod cannot be found, a
-# [PodNotFound](#PodNotFound) error is returned.
-# Containers in a pod are killed independently. If there is an error killing one container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was killed with no errors, the pod ID is returned.
-# See also [StopPod](StopPod).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.KillPod '{"name": "foobar", "signal": 15}'
-# {
-# "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f"
-# }
-# ~~~
-method KillPod(name: string, signal: int) -> (pod: string)
-
-# PausePod takes the name or ID of a pod and pauses the running containers associated with it. If the pod cannot be found,
-# a [PodNotFound](#PodNotFound) error will be returned.
-# Containers in a pod are paused independently. If there is an error pausing one container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was paused with no errors, the pod ID is returned.
-# See also [UnpausePod](#UnpausePod).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.PausePod '{"name": "foobar"}'
-# {
-# "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f"
-# }
-# ~~~
-method PausePod(name: string) -> (pod: string)
-
-# UnpausePod takes the name or ID of a pod and unpauses the paused containers associated with it. If the pod cannot be
-# found, a [PodNotFound](#PodNotFound) error will be returned.
-# Containers in a pod are unpaused independently. If there is an error unpausing one container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was unpaused with no errors, the pod ID is returned.
-# See also [PausePod](#PausePod).
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.UnpausePod '{"name": "foobar"}'
-# {
-# "pod": "1840835294cf076a822e4e12ba4152411f131bd869e7f6a4e8b16df9b0ea5c7f"
-# }
-# ~~~
-method UnpausePod(name: string) -> (pod: string)
-
-# RemovePod takes the name or ID of a pod as well a boolean representing whether a running
-# container in the pod can be stopped and removed. If a pod has containers associated with it, and force is not true,
-# an error will occur.
-# If the pod cannot be found by name or ID, a [PodNotFound](#PodNotFound) error will be returned.
-# Containers in a pod are removed independently. If there is an error removing any container, the ID of those containers
-# will be returned in a list, along with the ID of the pod in a [PodContainerError](#PodContainerError).
-# If the pod was removed with no errors, the pod ID is returned.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.RemovePod '{"name": "62f4fd98cb57", "force": "true"}'
-# {
-# "pod": "62f4fd98cb57f529831e8f90610e54bba74bd6f02920ffb485e15376ed365c20"
-# }
-# ~~~
-method RemovePod(name: string, force: bool) -> (pod: string)
-
-# This method has not be implemented yet.
-# method WaitPod() -> (notimplemented: NotImplemented)
-
-method TopPod(pod: string, latest: bool, descriptors: []string) -> (stats: []string)
-
-# GetPodStats takes the name or ID of a pod and returns a pod name and slice of ContainerStats structure which
-# contains attributes like memory and cpu usage. If the pod cannot be found, a [PodNotFound](#PodNotFound)
-# error will be returned. If the pod has no running containers associated with it, a [NoContainerRunning](#NoContainerRunning)
-# error will be returned.
-# #### Example
-# ~~~
-# $ varlink call unix:/run/podman/io.podman/io.podman.GetPodStats '{"name": "7f62b508b6f12b11d8fe02e"}'
-# {
-# "containers": [
-# {
-# "block_input": 0,
-# "block_output": 0,
-# "cpu": 2.833470544016107524276e-08,
-# "cpu_nano": 54363072,
-# "id": "a64b51f805121fe2c5a3dc5112eb61d6ed139e3d1c99110360d08b58d48e4a93",
-# "mem_limit": 12276146176,
-# "mem_perc": 7.974359265237864966003e-03,
-# "mem_usage": 978944,
-# "name": "quirky_heisenberg",
-# "net_input": 866,
-# "net_output": 7388,
-# "pids": 1,
-# "system_nano": 20000000
-# }
-# ],
-# "pod": "7f62b508b6f12b11d8fe02e0db4de6b9e43a7d7699b33a4fc0d574f6e82b4ebd"
-# }
-# ~~~
-method GetPodStats(name: string) -> (pod: string, containers: []ContainerStats)
-
-# GetPodsByStatus searches for pods whose status is included in statuses
-method GetPodsByStatus(statuses: []string) -> (pods: []string)
-
-# ImageExists talks a full or partial image ID or name and returns an int as to whether
-# the image exists in local storage. An int result of 0 means the image does exist in
-# local storage; whereas 1 indicates the image does not exists in local storage.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ImageExists '{"name": "imageddoesntexist"}'
-# {
-# "exists": 1
-# }
-# ~~~
-method ImageExists(name: string) -> (exists: int)
-
-# ImageTree returns the image tree for the provided image name or ID
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ImageTree '{"name": "alpine"}'
-# {
-# "tree": "Image ID: e7d92cdc71fe\nTags: [docker.io/library/alpine:latest]\nSize: 5.861MB\nImage Layers\n└── ID: 5216338b40a7 Size: 5.857MB Top Layer of: [docker.io/library/alpine:latest]\n"
-# }
-# ~~~
-method ImageTree(name: string, whatRequires: bool) -> (tree: string)
-
-# ContainerExists takes a full or partial container ID or name and returns an int as to
-# whether the container exists in local storage. A result of 0 means the container does
-# exists; whereas a result of 1 means it could not be found.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ContainerExists '{"name": "flamboyant_payne"}'{
-# "exists": 0
-# }
-# ~~~
-method ContainerExists(name: string) -> (exists: int)
-
-# ContainerCheckPoint performs a checkpopint on a container by its name or full/partial container
-# ID. On successful checkpoint, the id of the checkpointed container is returned.
-method ContainerCheckpoint(name: string, keep: bool, leaveRunning: bool, tcpEstablished: bool) -> (id: string)
-
-# ContainerRestore restores a container that has been checkpointed. The container to be restored can
-# be identified by its name or full/partial container ID. A successful restore will result in the return
-# of the container's ID.
-method ContainerRestore(name: string, keep: bool, tcpEstablished: bool) -> (id: string)
-
-# ContainerRunlabel runs executes a command as described by a given container image label.
-method ContainerRunlabel(runlabel: Runlabel) -> ()
-
-# ExecContainer executes a command in the given container.
-method ExecContainer(opts: ExecOpts) -> ()
-
-# ListContainerMounts gathers all the mounted container mount points and returns them as an array
-# of strings
-# #### Example
-# ~~~
-# $ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts
-# {
-# "mounts": {
-# "04e4c255269ed2545e7f8bd1395a75f7949c50c223415c00c1d54bfa20f3b3d9": "/var/lib/containers/storage/overlay/a078925828f57e20467ca31cfca8a849210d21ec7e5757332b72b6924f441c17/merged",
-# "1d58c319f9e881a644a5122ff84419dccf6d138f744469281446ab243ef38924": "/var/lib/containers/storage/overlay/948fcf93f8cb932f0f03fd52e3180a58627d547192ffe3b88e0013b98ddcd0d2/merged"
-# }
-# }
-# ~~~
-method ListContainerMounts() -> (mounts: [string]string)
-
-# MountContainer mounts a container by name or full/partial ID. Upon a successful mount, the destination
-# mount is returned as a string.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.MountContainer '{"name": "jolly_shannon"}'{
-# "path": "/var/lib/containers/storage/overlay/419eeb04e783ea159149ced67d9fcfc15211084d65e894792a96bedfae0470ca/merged"
-# }
-# ~~~
-method MountContainer(name: string) -> (path: string)
-
-# UnmountContainer umounts a container by its name or full/partial container ID.
-# #### Example
-# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.UnmountContainer '{"name": "jolly_shannon", "force": false}'
-# {}
-# ~~~
-method UnmountContainer(name: string, force: bool) -> ()
-
-# ImagesPrune removes all unused images from the local store. Upon successful pruning,
-# the IDs of the removed images are returned.
-method ImagesPrune(all: bool, filter: []string) -> (pruned: []string)
-
-# This function is not implemented yet.
-# method ListContainerPorts(name: string) -> (notimplemented: NotImplemented)
-
-# GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
-# and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
-method GenerateKube(name: string, service: bool) -> (pod: KubePodService)
-
-# ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML)
-# like that created by GenerateKube. See also [GenerateKube](GenerateKube).
-# method ReplayKube() -> (notimplemented: NotImplemented)
-
-# ContainerConfig returns a container's config in string form. This call is for
-# development of Podman only and generally should not be used.
-method ContainerConfig(name: string) -> (config: string)
-
-# ContainerArtifacts returns a container's artifacts in string form. This call is for
-# development of Podman only and generally should not be used.
-method ContainerArtifacts(name: string, artifactName: string) -> (config: string)
-
-# ContainerInspectData returns a container's inspect data in string form. This call is for
-# development of Podman only and generally should not be used.
-method ContainerInspectData(name: string, size: bool) -> (config: string)
-
-# ContainerStateData returns a container's state config in string form. This call is for
-# development of Podman only and generally should not be used.
-method ContainerStateData(name: string) -> (config: string)
-
-# PodStateData returns inspectr level information of a given pod in string form. This call is for
-# development of Podman only and generally should not be used.
-method PodStateData(name: string) -> (config: string)
-
-# This call is for the development of Podman only and should not be used.
-method CreateFromCC(in: []string) -> (id: string)
-
-# Spec returns the oci spec for a container. This call is for development of Podman only and generally should not be used.
-method Spec(name: string) -> (config: string)
-
-# Sendfile allows a remote client to send a file to the host
-method SendFile(type: string, length: int) -> (file_handle: string)
-
-# ReceiveFile allows the host to send a remote client a file
-method ReceiveFile(path: string, delete: bool) -> (len: int)
-
-# VolumeCreate creates a volume on a remote host
-method VolumeCreate(options: VolumeCreateOpts) -> (volumeName: string)
-
-# VolumeRemove removes a volume on a remote host
-method VolumeRemove(options: VolumeRemoveOpts) -> (successes: []string, failures: [string]string)
-
-# GetVolumes gets slice of the volumes on a remote host
-method GetVolumes(args: []string, all: bool) -> (volumes: []Volume)
-
-# InspectVolume inspects a single volume. Returns inspect JSON in the form of a
-# string.
-method InspectVolume(name: string) -> (volume: string)
-
-# VolumesPrune removes unused volumes on the host
-method VolumesPrune() -> (prunedNames: []string, prunedErrors: []string)
-
-# ImageSave allows you to save an image from the local image storage to a tarball
-method ImageSave(options: ImageSaveOptions) -> (reply: MoreResponse)
-
-# GetPodsByContext allows you to get a list pod ids depending on all, latest, or a list of
-# pod names. The definition of latest pod means the latest by creation date. In a multi-
-# user environment, results might differ from what you expect.
-method GetPodsByContext(all: bool, latest: bool, args: []string) -> (pods: []string)
-
-# LoadImage allows you to load an image into local storage from a tarball.
-method LoadImage(name: string, inputFile: string, quiet: bool, deleteFile: bool) -> (reply: MoreResponse)
-
-# GetEvents returns known libpod events filtered by the options provided.
-method GetEvents(filter: []string, since: string, until: string) -> (events: Event)
-
-# Diff returns a diff between libpod objects
-method Diff(name: string) -> (diffs: []DiffInfo)
-
-# GetLayersMapWithImageInfo is for the development of Podman and should not be used.
-method GetLayersMapWithImageInfo() -> (layerMap: string)
-
-# BuildImageHierarchyMap is for the development of Podman and should not be used.
-method BuildImageHierarchyMap(name: string) -> (imageInfo: string)
-
-# ImageNotFound means the image could not be found by the provided name or ID in local storage.
-error ImageNotFound (id: string, reason: string)
-
-# ContainerNotFound means the container could not be found by the provided name or ID in local storage.
-error ContainerNotFound (id: string, reason: string)
-
-# NoContainerRunning means none of the containers requested are running in a command that requires a running container.
-error NoContainerRunning ()
-
-# PodNotFound means the pod could not be found by the provided name or ID in local storage.
-error PodNotFound (name: string, reason: string)
-
-# VolumeNotFound means the volume could not be found by the name or ID in local storage.
-error VolumeNotFound (id: string, reason: string)
-
-# PodContainerError means a container associated with a pod failed to perform an operation. It contains
-# a container ID of the container that failed.
-error PodContainerError (podname: string, errors: []PodContainerErrorData)
-
-# NoContainersInPod means a pod has no containers on which to perform the operation. It contains
-# the pod ID.
-error NoContainersInPod (name: string)
-
-# InvalidState indicates that a container or pod was in an improper state for the requested operation
-error InvalidState (id: string, reason: string)
-
-# ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message
-# is includes as part of the error's text.
-error ErrorOccurred (reason: string)
-
-# RuntimeErrors generally means a runtime could not be found or gotten.
-error RuntimeError (reason: string)
-
-# The Podman endpoint requires that you use a streaming connection.
-error WantsMoreRequired (reason: string)
-
-# Container is already stopped
-error ErrCtrStopped (id: string)
-
-# This function requires CGroupsV2 to run in rootless mode.
-error ErrRequiresCgroupsV2ForRootless(reason: string)
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
deleted file mode 100644
index 38354a790..000000000
--- a/pkg/varlinkapi/attach.go
+++ /dev/null
@@ -1,144 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "bufio"
- "context"
- "io"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/libpod/events"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/containers/podman/v2/pkg/varlinkapi/virtwriter"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/tools/remotecommand"
-)
-
-func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.PipeReader, *io.PipeWriter, *define.AttachStreams) {
-
- // These are the varlink sockets
- reader := call.Call.Reader
- writer := call.Call.Writer
-
- // This pipe is used to pass stdin from the client to the input stream
- // once the msg has been "decoded"
- pr, pw := io.Pipe()
-
- stdoutWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.ToStdout)
- // TODO if runc ever starts passing stderr, we can too
- // stderrWriter := NewVirtWriteCloser(writer, ToStderr)
-
- streams := define.AttachStreams{
- OutputStream: stdoutWriter,
- InputStream: bufio.NewReader(pr),
- // Runc eats the error stream
- ErrorStream: stdoutWriter,
- AttachInput: true,
- AttachOutput: true,
- // Runc eats the error stream
- AttachError: true,
- }
- return reader, writer, pr, pw, &streams
-}
-
-// Attach connects to a containers console
-func (i *VarlinkAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys string, start bool) error {
- var finalErr error
- resize := make(chan remotecommand.TerminalSize)
- errChan := make(chan error)
-
- if !call.WantsUpgrade() {
- return call.ReplyErrorOccurred("client must use upgraded connection to attach")
- }
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- state, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if !start && state != define.ContainerStateRunning {
- return call.ReplyErrorOccurred("container must be running to attach")
- }
-
- // ACK the client upgrade request
- if err := call.ReplyAttach(); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- reader, writer, _, pw, streams := setupStreams(call)
- go func() {
- if err := virtwriter.Reader(reader, nil, nil, pw, resize, nil); err != nil {
- errChan <- err
- }
- }()
-
- if state == define.ContainerStateRunning {
- finalErr = attach(ctr, streams, detachKeys, resize, errChan)
- } else {
- finalErr = startAndAttach(ctr, streams, detachKeys, resize, errChan)
- }
-
- exitCode := define.ExitCode(finalErr)
- if finalErr != define.ErrDetach && finalErr != nil {
- logrus.Error(finalErr)
- } else {
- if ecode, err := ctr.Wait(); err != nil {
- if errors.Cause(err) == define.ErrNoSuchCtr {
- // Check events
- event, err := i.Runtime.GetLastContainerEvent(context.Background(), ctr.ID(), events.Exited)
- if err != nil {
- logrus.Errorf("Cannot get exit code: %v", err)
- exitCode = define.ExecErrorCodeNotFound
- } else {
- exitCode = event.ContainerExitCode
- }
- } else {
- exitCode = define.ExitCode(err)
- }
- } else {
- exitCode = int(ecode)
- }
- }
-
- if ctr.AutoRemove() {
- err := i.Runtime.RemoveContainer(getContext(), ctr, false, false)
- if err != nil {
- logrus.Errorf("Failed to remove container %s: %s", ctr.ID(), err.Error())
- }
- }
-
- if err = virtwriter.HangUp(writer, uint32(exitCode)); err != nil {
- logrus.Errorf("Failed to HANG-UP attach to %s: %s", ctr.ID(), err.Error())
- }
- return call.Writer.Flush()
-}
-
-func attach(ctr *libpod.Container, streams *define.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
- go func() {
- if err := ctr.Attach(streams, detachKeys, resize); err != nil {
- errChan <- err
- }
- }()
- attachError := <-errChan
- return attachError
-}
-
-func startAndAttach(ctr *libpod.Container, streams *define.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
- var finalErr error
- attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, false)
- if err != nil {
- return err
- }
- select {
- case attachChanErr := <-attachChan:
- finalErr = attachChanErr
- case chanError := <-errChan:
- finalErr = chanError
- }
- return finalErr
-}
diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go
deleted file mode 100644
index 50e6fb833..000000000
--- a/pkg/varlinkapi/config.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "github.com/containers/podman/v2/libpod"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/spf13/cobra"
-)
-
-// VarlinkAPI is the basic varlink struct for libpod
-type VarlinkAPI struct {
- Cli *cobra.Command
- iopodman.VarlinkInterface
- Runtime *libpod.Runtime
-}
-
-// New creates a new varlink client
-func New(cli *cobra.Command, runtime *libpod.Runtime) *iopodman.VarlinkInterface {
- lp := VarlinkAPI{Cli: cli, Runtime: runtime}
- return iopodman.VarlinkNew(&lp)
-}
diff --git a/pkg/varlinkapi/container.go b/pkg/varlinkapi/container.go
deleted file mode 100644
index c4e8c1feb..000000000
--- a/pkg/varlinkapi/container.go
+++ /dev/null
@@ -1,928 +0,0 @@
-package varlinkapi
-
-import (
- "context"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "regexp"
- "runtime"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/containers/image/v5/types"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/libpod/image"
- "github.com/containers/podman/v2/pkg/timetype"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/go-units"
- "github.com/google/shlex"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- v1 "k8s.io/api/core/v1"
-)
-
-const (
- cidTruncLength = 12
- podTruncLength = 12
- iidTruncLength = 12
- cmdTruncLength = 17
-)
-
-// PsOptions describes the struct being formed for ps.
-type PsOptions struct {
- All bool
- Format string
- Last int
- Latest bool
- NoTrunc bool
- Pod bool
- Quiet bool
- Size bool
- Sort string
- Namespace bool
- Sync bool
-}
-
-// BatchContainerStruct is the return object from BatchContainer and contains
-// container related information.
-type BatchContainerStruct struct {
- ConConfig *libpod.ContainerConfig
- ConState define.ContainerStatus
- ExitCode int32
- Exited bool
- Pid int
- StartedTime time.Time
- ExitedTime time.Time
- Size *ContainerSize
-}
-
-// PsContainerOutput is the struct being returned from a parallel
-// batch operation.
-type PsContainerOutput struct {
- ID string
- Image string
- ImageID string
- Command string
- Created string
- Ports string
- Names string
- IsInfra bool
- Status string
- State define.ContainerStatus
- Pid int
- Size *ContainerSize
- Pod string
- PodName string
- CreatedAt time.Time
- ExitedAt time.Time
- StartedAt time.Time
- Labels map[string]string
- PID string
- Cgroup string
- IPC string
- MNT string
- NET string
- PIDNS string
- User string
- UTS string
- Mounts string
-}
-
-// Namespace describes output for ps namespace.
-type Namespace struct {
- PID string `json:"pid,omitempty"`
- Cgroup string `json:"cgroup,omitempty"`
- IPC string `json:"ipc,omitempty"`
- MNT string `json:"mnt,omitempty"`
- NET string `json:"net,omitempty"`
- PIDNS string `json:"pidns,omitempty"`
- User string `json:"user,omitempty"`
- UTS string `json:"uts,omitempty"`
-}
-
-// ContainerSize holds the size of the container's root filesystem and top
-// read-write layer.
-type ContainerSize struct {
- RootFsSize int64 `json:"rootFsSize"`
- RwSize int64 `json:"rwSize"`
-}
-
-// NewBatchContainer runs a batch process under one lock to get container information and only
-// be called in PBatch.
-func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions) (PsContainerOutput, error) {
- var (
- conState define.ContainerStatus
- command string
- created string
- status string
- exitedAt time.Time
- startedAt time.Time
- exitCode int32
- err error
- pid int
- size *ContainerSize
- ns *Namespace
- pso PsContainerOutput
- )
- batchErr := ctr.Batch(func(c *libpod.Container) error {
- if opts.Sync {
- if err := c.Sync(); err != nil {
- return err
- }
- }
-
- conState, err = c.State()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container state")
- }
- command = strings.Join(c.Command(), " ")
- created = units.HumanDuration(time.Since(c.CreatedTime())) + " ago"
-
- exitCode, _, err = c.ExitCode()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container exit code")
- }
- startedAt, err = c.StartedTime()
- if err != nil {
- logrus.Errorf("error getting started time for %q: %v", c.ID(), err)
- }
- exitedAt, err = c.FinishedTime()
- if err != nil {
- logrus.Errorf("error getting exited time for %q: %v", c.ID(), err)
- }
- if opts.Namespace {
- pid, err = c.PID()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container pid")
- }
- ns = GetNamespaces(pid)
- }
- if opts.Size {
- size = new(ContainerSize)
-
- rootFsSize, err := c.RootFsSize()
- if err != nil {
- logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err)
- }
-
- rwSize, err := c.RWSize()
- if err != nil {
- logrus.Errorf("error getting rw size for %q: %v", c.ID(), err)
- }
-
- size.RootFsSize = rootFsSize
- size.RwSize = rwSize
- }
-
- return nil
- })
-
- if batchErr != nil {
- return pso, batchErr
- }
-
- switch conState.String() {
- case define.ContainerStateExited.String():
- fallthrough
- case define.ContainerStateStopped.String():
- exitedSince := units.HumanDuration(time.Since(exitedAt))
- status = fmt.Sprintf("Exited (%d) %s ago", exitCode, exitedSince)
- case define.ContainerStateRunning.String():
- status = "Up " + units.HumanDuration(time.Since(startedAt)) + " ago"
- case define.ContainerStatePaused.String():
- status = "Paused"
- case define.ContainerStateCreated.String(), define.ContainerStateConfigured.String():
- status = "Created"
- case define.ContainerStateRemoving.String():
- status = "Removing"
- default:
- status = "Error"
- }
-
- imageID, imageName := ctr.Image()
- cid := ctr.ID()
- podID := ctr.PodID()
- if !opts.NoTrunc {
- cid = cid[0:cidTruncLength]
- if len(podID) > podTruncLength {
- podID = podID[0:podTruncLength]
- }
- if len(command) > cmdTruncLength {
- command = command[0:cmdTruncLength] + "..."
- }
- if len(imageID) > iidTruncLength {
- imageID = imageID[0:iidTruncLength]
- }
- }
-
- ports, err := ctr.PortMappings()
- if err != nil {
- logrus.Errorf("unable to lookup namespace container for %s", ctr.ID())
- }
-
- pso.ID = cid
- pso.Image = imageName
- pso.ImageID = imageID
- pso.Command = command
- pso.Created = created
- pso.Ports = portsToString(ports)
- pso.Names = ctr.Name()
- pso.IsInfra = ctr.IsInfra()
- pso.Status = status
- pso.State = conState
- pso.Pid = pid
- pso.Size = size
- pso.ExitedAt = exitedAt
- pso.CreatedAt = ctr.CreatedTime()
- pso.StartedAt = startedAt
- pso.Labels = ctr.Labels()
- pso.Mounts = strings.Join(ctr.UserVolumes(), " ")
-
- // Add pod name and pod ID if requested by user.
- // No need to look up the pod if its ID is empty.
- if opts.Pod && len(podID) > 0 {
- // The pod name is not in the container definition
- // so we need to retrieve it using the pod ID.
- var podName string
- pod, err := r.LookupPod(podID)
- if err != nil {
- logrus.Errorf("unable to lookup pod for container %s", ctr.ID())
- } else {
- podName = pod.Name()
- }
-
- pso.Pod = podID
- pso.PodName = podName
- }
-
- if opts.Namespace {
- pso.Cgroup = ns.Cgroup
- pso.IPC = ns.IPC
- pso.MNT = ns.MNT
- pso.NET = ns.NET
- pso.User = ns.User
- pso.UTS = ns.UTS
- pso.PIDNS = ns.PIDNS
- }
-
- return pso, nil
-}
-
-type batchFunc func() (PsContainerOutput, error)
-
-type workerInput struct {
- parallelFunc batchFunc
- opts PsOptions
- cid string
- job int
-}
-
-// worker is a "threaded" worker that takes jobs from the channel "queue".
-func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results chan<- PsContainerOutput, errors chan<- error) {
- for j := range jobs {
- r, err := j.parallelFunc()
- // If we find an error, we return just the error.
- if err != nil {
- errors <- err
- } else {
- // Return the result.
- results <- r
- }
- wg.Done()
- }
-}
-
-// GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
-func GenerateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
- switch filter {
- case "id":
- return func(c *libpod.Container) bool {
- return strings.Contains(c.ID(), filterValue)
- }, nil
- case "label":
- var filterArray = strings.SplitN(filterValue, "=", 2)
- var filterKey = filterArray[0]
- if len(filterArray) > 1 {
- filterValue = filterArray[1]
- } else {
- filterValue = ""
- }
- return func(c *libpod.Container) bool {
- for labelKey, labelValue := range c.Labels() {
- if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
- return true
- }
- }
- return false
- }, nil
- case "name":
- return func(c *libpod.Container) bool {
- match, err := regexp.MatchString(filterValue, c.Name())
- if err != nil {
- return false
- }
- return match
- }, nil
- case "exited":
- exitCode, err := strconv.ParseInt(filterValue, 10, 32)
- if err != nil {
- return nil, errors.Wrapf(err, "exited code out of range %q", filterValue)
- }
- return func(c *libpod.Container) bool {
- ec, exited, err := c.ExitCode()
- if ec == int32(exitCode) && err == nil && exited {
- return true
- }
- return false
- }, nil
- case "status":
- if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
- return nil, errors.Errorf("%s is not a valid status", filterValue)
- }
- return func(c *libpod.Container) bool {
- status, err := c.State()
- if err != nil {
- return false
- }
- if filterValue == "stopped" {
- filterValue = "exited"
- }
- state := status.String()
- if status == define.ContainerStateConfigured {
- state = "created"
- } else if status == define.ContainerStateStopped {
- state = "exited"
- }
- return state == filterValue
- }, nil
- case "ancestor":
- // This needs to refine to match docker
- // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) {
- return true
- }
- return false
- }, nil
- case "before":
- ctr, err := r.LookupContainer(filterValue)
- if err != nil {
- return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
- }
- containerConfig := ctr.Config()
- createTime := containerConfig.CreatedTime
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.After(cc.CreatedTime)
- }, nil
- case "since":
- ctr, err := r.LookupContainer(filterValue)
- if err != nil {
- return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
- }
- containerConfig := ctr.Config()
- createTime := containerConfig.CreatedTime
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.Before(cc.CreatedTime)
- }, nil
- case "volume":
- //- volume=(<volume-name>|<mount-point-destination>)
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- var dest string
- arr := strings.Split(filterValue, ":")
- source := arr[0]
- if len(arr) == 2 {
- dest = arr[1]
- }
- for _, mount := range containerConfig.Spec.Mounts {
- if dest != "" && (mount.Source == source && mount.Destination == dest) {
- return true
- }
- if dest == "" && mount.Source == source {
- return true
- }
- }
- return false
- }, nil
- case "health":
- return func(c *libpod.Container) bool {
- hcStatus, err := c.HealthCheckStatus()
- if err != nil {
- return false
- }
- return hcStatus == filterValue
- }, nil
- case "until":
- ts, err := timetype.GetTimestamp(filterValue, time.Now())
- if err != nil {
- return nil, err
- }
- seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
- if err != nil {
- return nil, err
- }
- until := time.Unix(seconds, nanoseconds)
- return func(c *libpod.Container) bool {
- if !until.IsZero() && c.CreatedTime().After((until)) {
- return true
- }
- return false
- }, nil
- }
- return nil, errors.Errorf("%s is an invalid filter", filter)
-}
-
-// GetPsContainerOutput returns a slice of containers specifically for ps output.
-func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, maxWorkers int) ([]PsContainerOutput, error) {
- var (
- filterFuncs []libpod.ContainerFilter
- outputContainers []*libpod.Container
- )
-
- if len(filters) > 0 {
- for _, f := range filters {
- filterSplit := strings.SplitN(f, "=", 2)
- if len(filterSplit) < 2 {
- return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
- }
- generatedFunc, err := GenerateContainerFilterFuncs(filterSplit[0], filterSplit[1], r)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid filter")
- }
- filterFuncs = append(filterFuncs, generatedFunc)
- }
- }
- if !opts.Latest {
- // Get all containers.
- containers, err := r.GetContainers(filterFuncs...)
- if err != nil {
- return nil, err
- }
-
- // We only want the last few containers.
- if opts.Last > 0 && opts.Last <= len(containers) {
- return nil, errors.Errorf("--last not yet supported")
- } else {
- outputContainers = containers
- }
- } else {
- // Get just the latest container.
- // Ignore filters.
- latestCtr, err := r.GetLatestContainer()
- if err != nil {
- return nil, err
- }
-
- outputContainers = []*libpod.Container{latestCtr}
- }
-
- pss := PBatch(r, outputContainers, maxWorkers, opts)
- return pss, nil
-}
-
-// PBatch performs batch operations on a container in parallel. It spawns the
-// number of workers relative to the number of parallel operations desired.
-func PBatch(r *libpod.Runtime, containers []*libpod.Container, workers int, opts PsOptions) []PsContainerOutput {
- var wg sync.WaitGroup
- psResults := []PsContainerOutput{}
-
- // If the number of containers in question is less than the number of
- // proposed parallel operations, we shouldn't spawn so many workers.
- if workers > len(containers) {
- workers = len(containers)
- }
-
- jobs := make(chan workerInput, len(containers))
- results := make(chan PsContainerOutput, len(containers))
- batchErrors := make(chan error, len(containers))
-
- // Create the workers.
- for w := 1; w <= workers; w++ {
- go worker(&wg, jobs, results, batchErrors)
- }
-
- // Add jobs to the workers.
- for i, j := range containers {
- j := j
- wg.Add(1)
- f := func() (PsContainerOutput, error) {
- return NewBatchContainer(r, j, opts)
- }
- jobs <- workerInput{
- parallelFunc: f,
- opts: opts,
- cid: j.ID(),
- job: i,
- }
- }
- close(jobs)
- wg.Wait()
- close(results)
- close(batchErrors)
- for err := range batchErrors {
- logrus.Errorf("unable to get container info: %q", err)
- }
- for res := range results {
- // We sort out running vs non-running here to save lots of copying
- // later.
- if !opts.All && !opts.Latest && opts.Last < 1 {
- if !res.IsInfra && res.State == define.ContainerStateRunning {
- psResults = append(psResults, res)
- }
- } else {
- psResults = append(psResults, res)
- }
- }
- return psResults
-}
-
-// BatchContainerOp is used in ps to reduce performance hits by "batching"
-// locks.
-func BatchContainerOp(ctr *libpod.Container, opts PsOptions) (BatchContainerStruct, error) {
- var (
- conConfig *libpod.ContainerConfig
- conState define.ContainerStatus
- err error
- exitCode int32
- exited bool
- pid int
- size *ContainerSize
- startedTime time.Time
- exitedTime time.Time
- )
-
- batchErr := ctr.Batch(func(c *libpod.Container) error {
- conConfig = c.Config()
- conState, err = c.State()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container state")
- }
-
- exitCode, exited, err = c.ExitCode()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container exit code")
- }
- startedTime, err = c.StartedTime()
- if err != nil {
- logrus.Errorf("error getting started time for %q: %v", c.ID(), err)
- }
- exitedTime, err = c.FinishedTime()
- if err != nil {
- logrus.Errorf("error getting exited time for %q: %v", c.ID(), err)
- }
-
- if !opts.Size && !opts.Namespace {
- return nil
- }
-
- if opts.Namespace {
- pid, err = c.PID()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container pid")
- }
- }
- if opts.Size {
- size = new(ContainerSize)
-
- rootFsSize, err := c.RootFsSize()
- if err != nil {
- logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err)
- }
-
- rwSize, err := c.RWSize()
- if err != nil {
- logrus.Errorf("error getting rw size for %q: %v", c.ID(), err)
- }
-
- size.RootFsSize = rootFsSize
- size.RwSize = rwSize
- }
- return nil
- })
- if batchErr != nil {
- return BatchContainerStruct{}, batchErr
- }
- return BatchContainerStruct{
- ConConfig: conConfig,
- ConState: conState,
- ExitCode: exitCode,
- Exited: exited,
- Pid: pid,
- StartedTime: startedTime,
- ExitedTime: exitedTime,
- Size: size,
- }, nil
-}
-
-// GetNamespaces returns a populated namespace struct.
-func GetNamespaces(pid int) *Namespace {
- ctrPID := strconv.Itoa(pid)
- cgroup, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
- ipc, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
- mnt, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
- net, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
- pidns, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
- user, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
- uts, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
-
- return &Namespace{
- PID: ctrPID,
- Cgroup: cgroup,
- IPC: ipc,
- MNT: mnt,
- NET: net,
- PIDNS: pidns,
- User: user,
- UTS: uts,
- }
-}
-
-// GetNamespaceInfo is an exported wrapper for getNamespaceInfo
-func GetNamespaceInfo(path string) (string, error) {
- return getNamespaceInfo(path)
-}
-
-func getNamespaceInfo(path string) (string, error) {
- val, err := os.Readlink(path)
- if err != nil {
- return "", errors.Wrapf(err, "error getting info from %q", path)
- }
- return getStrFromSquareBrackets(val), nil
-}
-
-// getStrFromSquareBrackets gets the string inside [] from a string.
-func getStrFromSquareBrackets(cmd string) string {
- reg := regexp.MustCompile(`.*\[|\].*`)
- arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
- return strings.Join(arr, ",")
-}
-
-func comparePorts(i, j ocicni.PortMapping) bool {
- if i.ContainerPort != j.ContainerPort {
- return i.ContainerPort < j.ContainerPort
- }
-
- if i.HostIP != j.HostIP {
- return i.HostIP < j.HostIP
- }
-
- if i.HostPort != j.HostPort {
- return i.HostPort < j.HostPort
- }
-
- return i.Protocol < j.Protocol
-}
-
-// formatGroup returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto>
-// e.g 0.0.0.0:1000-1006->1000-1006/tcp.
-func formatGroup(key string, start, last int32) string {
- parts := strings.Split(key, "/")
- groupType := parts[0]
- var ip string
- if len(parts) > 1 {
- ip = parts[0]
- groupType = parts[1]
- }
- group := strconv.Itoa(int(start))
- if start != last {
- group = fmt.Sprintf("%s-%d", group, last)
- }
- if ip != "" {
- group = fmt.Sprintf("%s:%s->%s", ip, group, group)
- }
- return fmt.Sprintf("%s/%s", group, groupType)
-}
-
-// portsToString converts the ports used to a string of the from "port1, port2"
-// and also groups a continuous list of ports into a readable format.
-func portsToString(ports []ocicni.PortMapping) string {
- type portGroup struct {
- first int32
- last int32
- }
- var portDisplay []string
- if len(ports) == 0 {
- return ""
- }
- //Sort the ports, so grouping continuous ports become easy.
- sort.Slice(ports, func(i, j int) bool {
- return comparePorts(ports[i], ports[j])
- })
-
- // portGroupMap is used for grouping continuous ports.
- portGroupMap := make(map[string]*portGroup)
- var groupKeyList []string
-
- for _, v := range ports {
-
- hostIP := v.HostIP
- if hostIP == "" {
- hostIP = "0.0.0.0"
- }
- // If hostPort and containerPort are not same, consider as individual port.
- if v.ContainerPort != v.HostPort {
- portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
- continue
- }
-
- portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
-
- portgroup, ok := portGroupMap[portMapKey]
- if !ok {
- portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
- // This list is required to traverse portGroupMap.
- groupKeyList = append(groupKeyList, portMapKey)
- continue
- }
-
- if portgroup.last == (v.ContainerPort - 1) {
- portgroup.last = v.ContainerPort
- continue
- }
- }
- // For each portMapKey, format group list and append to output string.
- for _, portKey := range groupKeyList {
- group := portGroupMap[portKey]
- portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
- }
- return strings.Join(portDisplay, ", ")
-}
-
-// GetRunlabel is a helper function for runlabel; it gets the image if needed and begins the
-// construction of the runlabel output and environment variables.
-func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtime *libpod.Runtime, pull bool, inputCreds string, dockerRegistryOptions image.DockerRegistryOptions, authfile string, signaturePolicyPath string, output io.Writer) (string, string, error) {
- var (
- newImage *image.Image
- err error
- imageName string
- )
- if pull {
- var registryCreds *types.DockerAuthConfig
- if inputCreds != "" {
- creds, err := util.ParseRegistryCreds(inputCreds)
- if err != nil {
- return "", "", err
- }
- registryCreds = creds
- }
- dockerRegistryOptions.DockerRegistryCreds = registryCreds
- newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, &label, util.PullImageMissing)
- } else {
- newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage)
- }
- if err != nil {
- return "", "", errors.Wrapf(err, "unable to find image")
- }
-
- if len(newImage.Names()) < 1 {
- imageName = newImage.ID()
- } else {
- imageName = newImage.Names()[0]
- }
-
- runLabel, err := newImage.GetLabel(ctx, label)
- return runLabel, imageName, err
-}
-
-// GenerateRunlabelCommand generates the command that will eventually be executed by Podman.
-func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string, globalOpts string) ([]string, []string, error) {
- // If no name is provided, we use the image's basename instead.
- if name == "" {
- baseName, err := image.GetImageBaseName(imageName)
- if err != nil {
- return nil, nil, err
- }
- name = baseName
- }
- // The user provided extra arguments that need to be tacked onto the label's command.
- if len(extraArgs) > 0 {
- runLabel = fmt.Sprintf("%s %s", runLabel, strings.Join(extraArgs, " "))
- }
- cmd, err := GenerateCommand(runLabel, imageName, name, globalOpts)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "unable to generate command")
- }
- env := GenerateRunEnvironment(name, imageName, opts)
- env = append(env, "PODMAN_RUNLABEL_NESTED=1")
-
- envmap := envSliceToMap(env)
-
- envmapper := func(k string) string {
- switch k {
- case "OPT1":
- return envmap["OPT1"]
- case "OPT2":
- return envmap["OPT2"]
- case "OPT3":
- return envmap["OPT3"]
- case "PWD":
- // I would prefer to use os.getenv but it appears PWD is not in the os env list.
- d, err := os.Getwd()
- if err != nil {
- logrus.Error("unable to determine current working directory")
- return ""
- }
- return d
- }
- return ""
- }
- newS := os.Expand(strings.Join(cmd, " "), envmapper)
- cmd, err = shlex.Split(newS)
- if err != nil {
- return nil, nil, err
- }
- return cmd, env, nil
-}
-
-func envSliceToMap(env []string) map[string]string {
- m := make(map[string]string)
- for _, i := range env {
- split := strings.Split(i, "=")
- m[split[0]] = strings.Join(split[1:], " ")
- }
- return m
-}
-
-// GenerateKube generates kubernetes yaml based on a pod or container.
-func GenerateKube(name string, service bool, r *libpod.Runtime) (*v1.Pod, *v1.Service, error) {
- var (
- pod *libpod.Pod
- podYAML *v1.Pod
- err error
- container *libpod.Container
- servicePorts []v1.ServicePort
- serviceYAML v1.Service
- )
- // Get the container in question.
- container, err = r.LookupContainer(name)
- if err != nil {
- pod, err = r.LookupPod(name)
- if err != nil {
- return nil, nil, err
- }
- podYAML, servicePorts, err = pod.GenerateForKube()
- } else {
- if len(container.Dependencies()) > 0 {
- return nil, nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
- }
- podYAML, err = container.GenerateForKube()
- }
- if err != nil {
- return nil, nil, err
- }
-
- if service {
- serviceYAML = libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts)
- }
- return podYAML, &serviceYAML, nil
-}
-
-// Parallelize provides the maximum number of parallel workers (int) as calculated by a basic
-// heuristic. This can be overridden by the --max-workers primary switch to podman.
-func Parallelize(job string) int {
- numCpus := runtime.NumCPU()
- switch job {
- case "kill":
- if numCpus <= 3 {
- return numCpus * 3
- }
- return numCpus * 4
- case "pause":
- if numCpus <= 3 {
- return numCpus * 3
- }
- return numCpus * 4
- case "ps":
- return 8
- case "restart":
- return numCpus * 2
- case "rm":
- if numCpus <= 3 {
- return numCpus * 3
- } else {
- return numCpus * 4
- }
- case "stop":
- if numCpus <= 2 {
- return 4
- } else {
- return numCpus * 3
- }
- case "unpause":
- if numCpus <= 3 {
- return numCpus * 3
- }
- return numCpus * 4
- }
- return 3
-}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
deleted file mode 100644
index fef3b6476..000000000
--- a/pkg/varlinkapi/containers.go
+++ /dev/null
@@ -1,912 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "bufio"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/libpod/logs"
- "github.com/containers/podman/v2/pkg/cgroups"
- "github.com/containers/podman/v2/pkg/rootless"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/containers/podman/v2/pkg/varlinkapi/virtwriter"
- "github.com/containers/storage/pkg/archive"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/tools/remotecommand"
-)
-
-// ListContainers ...
-func (i *VarlinkAPI) ListContainers(call iopodman.VarlinkCall) error {
- var (
- listContainers []iopodman.Container
- )
-
- containers, err := i.Runtime.GetAllContainers()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- opts := PsOptions{
- Namespace: true,
- Size: true,
- }
- for _, ctr := range containers {
- batchInfo, err := BatchContainerOp(ctr, opts)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- listContainers = append(listContainers, makeListContainer(ctr.ID(), batchInfo))
- }
- return call.ReplyListContainers(listContainers)
-}
-
-func (i *VarlinkAPI) Ps(call iopodman.VarlinkCall, opts iopodman.PsOpts) error {
- var (
- containers []iopodman.PsContainer
- )
- maxWorkers := Parallelize("ps")
- psOpts := makePsOpts(opts)
- filters := []string{}
- if opts.Filters != nil {
- filters = *opts.Filters
- }
- psContainerOutputs, err := GetPsContainerOutput(i.Runtime, psOpts, filters, maxWorkers)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- for _, ctr := range psContainerOutputs {
- container := iopodman.PsContainer{
- Id: ctr.ID,
- Image: ctr.Image,
- Command: ctr.Command,
- Created: ctr.Created,
- Ports: ctr.Ports,
- Names: ctr.Names,
- IsInfra: ctr.IsInfra,
- Status: ctr.Status,
- State: ctr.State.String(),
- PidNum: int64(ctr.Pid),
- Pod: ctr.Pod,
- CreatedAt: ctr.CreatedAt.Format(time.RFC3339Nano),
- ExitedAt: ctr.ExitedAt.Format(time.RFC3339Nano),
- StartedAt: ctr.StartedAt.Format(time.RFC3339Nano),
- Labels: ctr.Labels,
- NsPid: ctr.PID,
- Cgroup: ctr.Cgroup,
- Ipc: ctr.Cgroup,
- Mnt: ctr.MNT,
- Net: ctr.NET,
- PidNs: ctr.PIDNS,
- User: ctr.User,
- Uts: ctr.UTS,
- Mounts: ctr.Mounts,
- }
- if ctr.Size != nil {
- container.RootFsSize = ctr.Size.RootFsSize
- container.RwSize = ctr.Size.RwSize
- }
- containers = append(containers, container)
- }
- return call.ReplyPs(containers)
-}
-
-// GetContainer ...
-func (i *VarlinkAPI) GetContainer(call iopodman.VarlinkCall, id string) error {
- ctr, err := i.Runtime.LookupContainer(id)
- if err != nil {
- return call.ReplyContainerNotFound(id, err.Error())
- }
- opts := PsOptions{
- Namespace: true,
- Size: true,
- }
- batchInfo, err := BatchContainerOp(ctr, opts)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyGetContainer(makeListContainer(ctr.ID(), batchInfo))
-}
-
-// getContainersByContext returns a slice of container ids based on all, latest, or a list
-func (i *VarlinkAPI) GetContainersByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error {
- var ids []string
-
- ctrs, err := getContainersByContext(all, latest, input, i.Runtime)
- if err != nil {
- if errors.Cause(err) == define.ErrNoSuchCtr {
- return call.ReplyContainerNotFound("", err.Error())
- }
- return call.ReplyErrorOccurred(err.Error())
- }
-
- for _, c := range ctrs {
- ids = append(ids, c.ID())
- }
- return call.ReplyGetContainersByContext(ids)
-}
-
-// GetContainersByStatus returns a slice of containers filtered by a libpod status
-func (i *VarlinkAPI) GetContainersByStatus(call iopodman.VarlinkCall, statuses []string) error {
- var (
- filterFuncs []libpod.ContainerFilter
- containers []iopodman.Container
- )
- for _, status := range statuses {
- lpstatus, err := define.StringToContainerStatus(status)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == lpstatus
- })
- }
- filteredContainers, err := i.Runtime.GetContainers(filterFuncs...)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- opts := PsOptions{Size: true, Namespace: true}
- for _, ctr := range filteredContainers {
- batchInfo, err := BatchContainerOp(ctr, opts)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- containers = append(containers, makeListContainer(ctr.ID(), batchInfo))
- }
- return call.ReplyGetContainersByStatus(containers)
-}
-
-// InspectContainer ...
-func (i *VarlinkAPI) InspectContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- data, err := ctr.Inspect(true)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- b, err := json.Marshal(data)
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to serialize"))
- }
- return call.ReplyInspectContainer(string(b))
-}
-
-// ListContainerProcesses ...
-func (i *VarlinkAPI) ListContainerProcesses(call iopodman.VarlinkCall, name string, opts []string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- containerState, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if containerState != define.ContainerStateRunning {
- return call.ReplyErrorOccurred(fmt.Sprintf("container %s is not running", name))
- }
- var psArgs []string
- psOpts := []string{"user", "pid", "ppid", "pcpu", "etime", "tty", "time", "comm"}
- if len(opts) > 1 {
- psOpts = opts
- }
- psArgs = append(psArgs, psOpts...)
- psOutput, err := ctr.GetContainerPidInformation(psArgs)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- return call.ReplyListContainerProcesses(psOutput)
-}
-
-// GetContainerLogs ...
-func (i *VarlinkAPI) GetContainerLogs(call iopodman.VarlinkCall, name string) error {
- var logs []string
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- logPath := ctr.LogPath()
-
- containerState, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if _, err := os.Stat(logPath); err != nil {
- if containerState == define.ContainerStateConfigured {
- return call.ReplyGetContainerLogs(logs)
- }
- }
- file, err := os.Open(logPath)
- if err != nil {
- return errors.Wrapf(err, "unable to read container log file")
- }
- defer file.Close()
- reader := bufio.NewReader(file)
- if call.WantsMore() {
- call.Continues = true
- }
- for {
- line, err := reader.ReadString('\n')
- // We've read the entire file
- if err == io.EOF {
- if !call.WantsMore() {
- // If this is a non-following log request, we return what we have
- break
- } else {
- // If we want to follow, return what we have, wipe the slice, and make
- // sure the container is still running before iterating.
- call.ReplyGetContainerLogs(logs)
- logs = []string{}
- time.Sleep(1 * time.Second)
- state, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if state != define.ContainerStateRunning && state != define.ContainerStatePaused {
- return call.ReplyErrorOccurred(fmt.Sprintf("%s is no longer running", ctr.ID()))
- }
-
- }
- } else if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- } else {
- logs = append(logs, line)
- }
- }
-
- call.Continues = false
-
- return call.ReplyGetContainerLogs(logs)
-}
-
-// ListContainerChanges ...
-func (i *VarlinkAPI) ListContainerChanges(call iopodman.VarlinkCall, name string) error {
- changes, err := i.Runtime.GetDiff("", name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- result := iopodman.ContainerChanges{}
- for _, change := range changes {
- switch change.Kind {
- case archive.ChangeModify:
- result.Changed = append(result.Changed, change.Path)
- case archive.ChangeDelete:
- result.Deleted = append(result.Deleted, change.Path)
- case archive.ChangeAdd:
- result.Added = append(result.Added, change.Path)
- }
- }
- return call.ReplyListContainerChanges(result)
-}
-
-// ExportContainer ...
-func (i *VarlinkAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- outputFile, err := ioutil.TempFile("", "varlink_recv")
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- defer outputFile.Close()
- if outPath == "" {
- outPath = outputFile.Name()
- }
- if err := ctr.Export(outPath); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyExportContainer(outPath)
-
-}
-
-// GetContainerStats ...
-func (i *VarlinkAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error {
- if rootless.IsRootless() {
- cgroupv2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if !cgroupv2 {
- return call.ReplyErrRequiresCgroupsV2ForRootless("rootless containers cannot report container stats")
- }
- }
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- containerStats, err := ctr.GetContainerStats(&define.ContainerStats{})
- if err != nil {
- if errors.Cause(err) == define.ErrCtrStateInvalid {
- return call.ReplyNoContainerRunning()
- }
- return call.ReplyErrorOccurred(err.Error())
- }
- cs := iopodman.ContainerStats{
- Id: ctr.ID(),
- Name: ctr.Name(),
- Cpu: containerStats.CPU,
- Cpu_nano: int64(containerStats.CPUNano),
- System_nano: int64(containerStats.SystemNano),
- Mem_usage: int64(containerStats.MemUsage),
- Mem_limit: int64(containerStats.MemLimit),
- Mem_perc: containerStats.MemPerc,
- Net_input: int64(containerStats.NetInput),
- Net_output: int64(containerStats.NetOutput),
- Block_input: int64(containerStats.BlockInput),
- Block_output: int64(containerStats.BlockOutput),
- Pids: int64(containerStats.PIDs),
- }
- return call.ReplyGetContainerStats(cs)
-}
-
-// StartContainer ...
-func (i *VarlinkAPI) StartContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- state, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if state == define.ContainerStateRunning || state == define.ContainerStatePaused {
- return call.ReplyErrorOccurred("container is already running or paused")
- }
- recursive := false
- if ctr.PodID() != "" {
- recursive = true
- }
- if err := ctr.Start(getContext(), recursive); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyStartContainer(ctr.ID())
-}
-
-// InitContainer initializes the container given by Varlink.
-func (i *VarlinkAPI) InitContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := ctr.Init(getContext(), false); err != nil {
- if errors.Cause(err) == define.ErrCtrStateInvalid {
- return call.ReplyInvalidState(ctr.ID(), err.Error())
- }
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyInitContainer(ctr.ID())
-}
-
-// StopContainer ...
-func (i *VarlinkAPI) StopContainer(call iopodman.VarlinkCall, name string, timeout int64) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := ctr.StopWithTimeout(uint(timeout)); err != nil {
- if errors.Cause(err) == define.ErrCtrStopped {
- return call.ReplyErrCtrStopped(ctr.ID())
- }
- if errors.Cause(err) == define.ErrCtrStateInvalid {
- return call.ReplyInvalidState(ctr.ID(), err.Error())
- }
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyStopContainer(ctr.ID())
-}
-
-// RestartContainer ...
-func (i *VarlinkAPI) RestartContainer(call iopodman.VarlinkCall, name string, timeout int64) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := ctr.RestartWithTimeout(getContext(), uint(timeout)); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyRestartContainer(ctr.ID())
-}
-
-// ContainerExists looks in local storage for the existence of a container
-func (i *VarlinkAPI) ContainerExists(call iopodman.VarlinkCall, name string) error {
- _, err := i.Runtime.LookupContainer(name)
- if errors.Cause(err) == define.ErrNoSuchCtr {
- return call.ReplyContainerExists(1)
- }
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyContainerExists(0)
-}
-
-// KillContainer kills a running container. If you want to use the default SIGTERM signal, just send a -1
-// for the signal arg.
-func (i *VarlinkAPI) KillContainer(call iopodman.VarlinkCall, name string, signal int64) error {
- killSignal := uint(syscall.SIGTERM)
- if signal != -1 {
- killSignal = uint(signal)
- }
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := ctr.Kill(killSignal); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyKillContainer(ctr.ID())
-}
-
-// PauseContainer ...
-func (i *VarlinkAPI) PauseContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := ctr.Pause(); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyPauseContainer(ctr.ID())
-}
-
-// UnpauseContainer ...
-func (i *VarlinkAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := ctr.Unpause(); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyUnpauseContainer(ctr.ID())
-}
-
-// WaitContainer ...
-func (i *VarlinkAPI) WaitContainer(call iopodman.VarlinkCall, name string, interval int64) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- exitCode, err := ctr.WaitWithInterval(time.Duration(interval))
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyWaitContainer(int64(exitCode))
-}
-
-// RemoveContainer ...
-func (i *VarlinkAPI) RemoveContainer(call iopodman.VarlinkCall, name string, force bool, removeVolumes bool) error {
- ctx := getContext()
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil {
- if errors.Cause(err) == define.ErrNoSuchCtr {
- return call.ReplyContainerExists(1)
- }
- if errors.Cause(err) == define.ErrCtrStateInvalid {
- return call.ReplyInvalidState(ctr.ID(), err.Error())
- }
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyRemoveContainer(ctr.ID())
-}
-
-// EvictContainer ...
-func (i *VarlinkAPI) EvictContainer(call iopodman.VarlinkCall, name string, removeVolumes bool) error {
- ctx := getContext()
- id, err := i.Runtime.EvictContainer(ctx, name, removeVolumes)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyEvictContainer(id)
-}
-
-// DeleteStoppedContainers ...
-func (i *VarlinkAPI) DeleteStoppedContainers(call iopodman.VarlinkCall) error {
- ctx := getContext()
- var deletedContainers []string
- containers, err := i.Runtime.GetAllContainers()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- for _, ctr := range containers {
- state, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if state != define.ContainerStateRunning {
- if err := i.Runtime.RemoveContainer(ctx, ctr, false, false); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- deletedContainers = append(deletedContainers, ctr.ID())
- }
- }
- return call.ReplyDeleteStoppedContainers(deletedContainers)
-}
-
-// GetAttachSockets ...
-func (i *VarlinkAPI) GetAttachSockets(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
-
- status, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- // If the container hasn't been run, we need to run init
- // so the conmon sockets get created.
- if status == define.ContainerStateConfigured || status == define.ContainerStateStopped {
- if err := ctr.Init(getContext(), false); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- }
-
- sockPath, err := ctr.AttachSocketPath()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- s := iopodman.Sockets{
- Container_id: ctr.ID(),
- Io_socket: sockPath,
- Control_socket: ctr.ControlSocketPath(),
- }
- return call.ReplyGetAttachSockets(s)
-}
-
-// ContainerCheckpoint ...
-func (i *VarlinkAPI) ContainerCheckpoint(call iopodman.VarlinkCall, name string, keep, leaveRunning, tcpEstablished bool) error {
- ctx := getContext()
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
-
- options := libpod.ContainerCheckpointOptions{
- Keep: keep,
- TCPEstablished: tcpEstablished,
- KeepRunning: leaveRunning,
- }
- if err := ctr.Checkpoint(ctx, options); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyContainerCheckpoint(ctr.ID())
-}
-
-// ContainerRestore ...
-func (i *VarlinkAPI) ContainerRestore(call iopodman.VarlinkCall, name string, keep, tcpEstablished bool) error {
- ctx := getContext()
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
-
- options := libpod.ContainerCheckpointOptions{
- Keep: keep,
- TCPEstablished: tcpEstablished,
- }
- if err := ctr.Restore(ctx, options); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyContainerRestore(ctr.ID())
-}
-
-// ContainerConfig returns just the container.config struct
-func (i *VarlinkAPI) ContainerConfig(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- config := ctr.Config()
- b, err := json.Marshal(config)
- if err != nil {
- return call.ReplyErrorOccurred("unable to serialize container config")
- }
- return call.ReplyContainerConfig(string(b))
-}
-
-// ContainerArtifacts returns an untouched container's artifact in string format
-func (i *VarlinkAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifactName string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- artifacts, err := ctr.GetArtifact(artifactName)
- if err != nil {
- return call.ReplyErrorOccurred("unable to get container artifacts")
- }
- b, err := json.Marshal(artifacts)
- if err != nil {
- return call.ReplyErrorOccurred("unable to serialize container artifacts")
- }
- return call.ReplyContainerArtifacts(string(b))
-}
-
-// ContainerInspectData returns the inspect data of a container in string format
-func (i *VarlinkAPI) ContainerInspectData(call iopodman.VarlinkCall, name string, size bool) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- data, err := ctr.Inspect(size)
- if err != nil {
- return call.ReplyErrorOccurred("unable to inspect container")
- }
- b, err := json.Marshal(data)
- if err != nil {
- return call.ReplyErrorOccurred("unable to serialize container inspect data")
- }
- return call.ReplyContainerInspectData(string(b))
-
-}
-
-// ContainerStateData returns a container's state data in string format
-func (i *VarlinkAPI) ContainerStateData(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- data, err := ctr.ContainerState()
- if err != nil {
- return call.ReplyErrorOccurred("unable to obtain container state")
- }
- b, err := json.Marshal(data)
- if err != nil {
- return call.ReplyErrorOccurred("unable to serialize container inspect data")
- }
- return call.ReplyContainerStateData(string(b))
-}
-
-// GetContainerStatsWithHistory is a varlink endpoint that returns container stats based on current and
-// previous statistics
-func (i *VarlinkAPI) GetContainerStatsWithHistory(call iopodman.VarlinkCall, prevStats iopodman.ContainerStats) error {
- con, err := i.Runtime.LookupContainer(prevStats.Id)
- if err != nil {
- return call.ReplyContainerNotFound(prevStats.Id, err.Error())
- }
- previousStats := ContainerStatsToLibpodContainerStats(prevStats)
- stats, err := con.GetContainerStats(&previousStats)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- cStats := iopodman.ContainerStats{
- Id: stats.ContainerID,
- Name: stats.Name,
- Cpu: stats.CPU,
- Cpu_nano: int64(stats.CPUNano),
- System_nano: int64(stats.SystemNano),
- Mem_usage: int64(stats.MemUsage),
- Mem_limit: int64(stats.MemLimit),
- Mem_perc: stats.MemPerc,
- Net_input: int64(stats.NetInput),
- Net_output: int64(stats.NetOutput),
- Block_input: int64(stats.BlockInput),
- Block_output: int64(stats.BlockOutput),
- Pids: int64(stats.PIDs),
- }
- return call.ReplyGetContainerStatsWithHistory(cStats)
-}
-
-// Spec ...
-func (i *VarlinkAPI) Spec(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- spec := ctr.Spec()
- b, err := json.Marshal(spec)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- return call.ReplySpec(string(b))
-}
-
-// GetContainersLogs is the varlink endpoint to obtain one or more container logs
-func (i *VarlinkAPI) GetContainersLogs(call iopodman.VarlinkCall, names []string, follow, latest bool, since string, tail int64, timestamps bool) error {
- var wg sync.WaitGroup
- if call.WantsMore() {
- call.Continues = true
- }
- sinceTime, err := time.Parse(time.RFC3339Nano, since)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- options := logs.LogOptions{
- Follow: follow,
- Since: sinceTime,
- Tail: tail,
- Timestamps: timestamps,
- }
-
- options.WaitGroup = &wg
- if len(names) > 1 {
- options.Multi = true
- }
- tailLen := int(tail)
- if tailLen < 0 {
- tailLen = 0
- }
- logChannel := make(chan *logs.LogLine, tailLen*len(names)+1)
- containers, err := getContainersByContext(false, latest, names, i.Runtime)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if err := i.Runtime.Log(getContext(), containers, &options, logChannel); err != nil {
- return err
- }
- go func() {
- wg.Wait()
- close(logChannel)
- }()
- for line := range logChannel {
- call.ReplyGetContainersLogs(newPodmanLogLine(line))
- if !call.Continues {
- break
- }
-
- }
- return call.ReplyGetContainersLogs(iopodman.LogLine{})
-}
-
-func newPodmanLogLine(line *logs.LogLine) iopodman.LogLine {
- return iopodman.LogLine{
- Device: line.Device,
- ParseLogType: line.ParseLogType,
- Time: line.Time.Format(time.RFC3339Nano),
- Msg: line.Msg,
- Cid: line.CID,
- }
-}
-
-// Top displays information about a container's running processes
-func (i *VarlinkAPI) Top(call iopodman.VarlinkCall, nameOrID string, descriptors []string) error {
- ctr, err := i.Runtime.LookupContainer(nameOrID)
- if err != nil {
- return call.ReplyContainerNotFound(ctr.ID(), err.Error())
- }
- topInfo, err := ctr.Top(descriptors)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyTop(topInfo)
-}
-
-// ExecContainer is the varlink endpoint to execute a command in a container
-func (i *VarlinkAPI) ExecContainer(call iopodman.VarlinkCall, opts iopodman.ExecOpts) error {
- if !call.WantsUpgrade() {
- return call.ReplyErrorOccurred("client must use upgraded connection to exec")
- }
-
- ctr, err := i.Runtime.LookupContainer(opts.Name)
- if err != nil {
- return call.ReplyContainerNotFound(opts.Name, err.Error())
- }
-
- state, err := ctr.State()
- if err != nil {
- return call.ReplyErrorOccurred(
- fmt.Sprintf("exec failed to obtain container %s state: %s", ctr.ID(), err.Error()))
- }
-
- if state != define.ContainerStateRunning {
- return call.ReplyErrorOccurred(
- fmt.Sprintf("exec requires a running container, %s is %s", ctr.ID(), state.String()))
- }
-
- // ACK the client upgrade request
- call.ReplyExecContainer()
-
- envs := make(map[string]string)
- if opts.Env != nil {
- // HACK: The Varlink API uses the old []string format for env,
- // storage as "k=v". Split on the = and turn into the new map
- // format.
- for _, env := range *opts.Env {
- splitEnv := strings.SplitN(env, "=", 2)
- if len(splitEnv) == 1 {
- logrus.Errorf("Got badly-formatted environment variable %q in exec", env)
- continue
- }
- envs[splitEnv[0]] = splitEnv[1]
- }
- }
-
- var user string
- if opts.User != nil {
- user = *opts.User
- }
-
- var workDir string
- if opts.Workdir != nil {
- workDir = *opts.Workdir
- }
-
- resizeChan := make(chan remotecommand.TerminalSize)
-
- reader, writer, _, pipeWriter, streams := setupStreams(call)
-
- type ExitCodeError struct {
- ExitCode uint32
- Error error
- }
- ecErrChan := make(chan ExitCodeError, 1)
-
- go func() {
- if err := virtwriter.Reader(reader, nil, nil, pipeWriter, resizeChan, nil); err != nil {
- ecErrChan <- ExitCodeError{
- define.ExecErrorCodeGeneric,
- err,
- }
- }
- }()
-
- execConfig := new(libpod.ExecConfig)
- execConfig.Command = opts.Cmd
- execConfig.Terminal = opts.Tty
- execConfig.Privileged = opts.Privileged
- execConfig.Environment = envs
- execConfig.User = user
- execConfig.WorkDir = workDir
- execConfig.DetachKeys = opts.DetachKeys
-
- go func() {
- ec, err := ctr.Exec(execConfig, streams, resizeChan)
- if err != nil {
- logrus.Errorf(err.Error())
- }
- ecErrChan <- ExitCodeError{
- uint32(ec),
- err,
- }
- }()
-
- ecErr := <-ecErrChan
-
- exitCode := define.TranslateExecErrorToExitCode(int(ecErr.ExitCode), ecErr.Error)
-
- if err = virtwriter.HangUp(writer, uint32(exitCode)); err != nil {
- logrus.Errorf("ExecContainer failed to HANG-UP on %s: %s", ctr.ID(), err.Error())
- }
-
- if err := call.Writer.Flush(); err != nil {
- logrus.Errorf("Exec Container err: %s", err.Error())
- }
-
- return ecErr.Error
-}
-
-// HealthCheckRun executes defined container's healthcheck command and returns the container's health status.
-func (i *VarlinkAPI) HealthCheckRun(call iopodman.VarlinkCall, nameOrID string) error {
- hcStatus, err := i.Runtime.HealthCheck(nameOrID)
- if err != nil && hcStatus != define.HealthCheckFailure {
- return call.ReplyErrorOccurred(err.Error())
- }
- status := define.HealthCheckUnhealthy
- if hcStatus == define.HealthCheckSuccess {
- status = define.HealthCheckHealthy
- }
- return call.ReplyHealthCheckRun(status)
-}
diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go
deleted file mode 100644
index 771e58089..000000000
--- a/pkg/varlinkapi/containers_create.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- iopodman "github.com/containers/podman/v2/pkg/varlink"
-)
-
-// CreateContainer ...
-func (i *VarlinkAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.Create) error {
- generic := VarlinkCreateToGeneric(config)
- ctr, _, err := CreateContainer(getContext(), &generic, i.Runtime)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyCreateContainer(ctr.ID())
-}
diff --git a/pkg/varlinkapi/create.go b/pkg/varlinkapi/create.go
deleted file mode 100644
index e9309a2d4..000000000
--- a/pkg/varlinkapi/create.go
+++ /dev/null
@@ -1,1155 +0,0 @@
-package varlinkapi
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "io"
- "os"
- "path/filepath"
- goruntime "runtime"
- "strconv"
- "strings"
- "syscall"
- "time"
-
- "github.com/containers/common/pkg/sysinfo"
- "github.com/containers/image/v5/manifest"
- "github.com/containers/podman/v2/cmd/podman/parse"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/libpod/image"
- ann "github.com/containers/podman/v2/pkg/annotations"
- "github.com/containers/podman/v2/pkg/autoupdate"
- "github.com/containers/podman/v2/pkg/cgroups"
- envLib "github.com/containers/podman/v2/pkg/env"
- "github.com/containers/podman/v2/pkg/errorhandling"
- "github.com/containers/podman/v2/pkg/inspect"
- ns "github.com/containers/podman/v2/pkg/namespaces"
- "github.com/containers/podman/v2/pkg/rootless"
- "github.com/containers/podman/v2/pkg/seccomp"
- cc "github.com/containers/podman/v2/pkg/spec"
- systemdGen "github.com/containers/podman/v2/pkg/systemd/generate"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/docker/go-connections/nat"
- "github.com/docker/go-units"
- "github.com/opentracing/opentracing-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-var DefaultKernelNamespaces = "cgroup,ipc,net,uts"
-
-func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
- var (
- healthCheck *manifest.Schema2HealthConfig
- err error
- cidFile *os.File
- )
- if c.Bool("trace") {
- span, _ := opentracing.StartSpanFromContext(ctx, "createContainer")
- defer span.Finish()
- }
- if c.Bool("rm") && c.String("restart") != "" && c.String("restart") != "no" {
- return nil, nil, errors.Errorf("the --rm option conflicts with --restart")
- }
-
- rtc, err := runtime.GetConfig()
- if err != nil {
- return nil, nil, err
- }
- rootfs := ""
- if c.Bool("rootfs") {
- rootfs = c.InputArgs[0]
- }
-
- if c.IsSet("cidfile") {
- cidFile, err = util.OpenExclusiveFile(c.String("cidfile"))
- if err != nil && os.IsExist(err) {
- return nil, nil, errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", c.String("cidfile"))
- }
- if err != nil {
- return nil, nil, errors.Errorf("error opening cidfile %s", c.String("cidfile"))
- }
- defer errorhandling.CloseQuiet(cidFile)
- defer errorhandling.SyncQuiet(cidFile)
- }
-
- imageName := ""
- rawImageName := ""
- var imageData *inspect.ImageData = nil
-
- // Set the storage if there is no rootfs specified
- if rootfs == "" {
- var writer io.Writer
- if !c.Bool("quiet") {
- writer = os.Stderr
- }
-
- if len(c.InputArgs) != 0 {
- rawImageName = c.InputArgs[0]
- } else {
- return nil, nil, errors.Errorf("error, image name not provided")
- }
-
- pullType, err := util.ValidatePullType(c.String("pull"))
- if err != nil {
- return nil, nil, err
- }
-
- overrideOS := c.String("override-os")
- overrideArch := c.String("override-arch")
- dockerRegistryOptions := image.DockerRegistryOptions{
- OSChoice: overrideOS,
- ArchitectureChoice: overrideArch,
- }
-
- newImage, err := runtime.ImageRuntime().New(ctx, rawImageName, rtc.Engine.SignaturePolicyPath, c.String("authfile"), writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullType)
- if err != nil {
- return nil, nil, err
- }
- imageData, err = newImage.InspectNoSize(ctx)
- if err != nil {
- return nil, nil, err
- }
-
- if overrideOS == "" && imageData.Os != goruntime.GOOS {
- logrus.Infof("Using %q (OS) image on %q host", imageData.Os, goruntime.GOOS)
- }
-
- if overrideArch == "" && imageData.Architecture != goruntime.GOARCH {
- logrus.Infof("Using %q (architecture) on %q host", imageData.Architecture, goruntime.GOARCH)
- }
-
- names := newImage.Names()
- if len(names) > 0 {
- imageName = names[0]
- } else {
- imageName = newImage.ID()
- }
-
- // if the user disabled the healthcheck with "none" or the no-healthcheck
- // options is provided, we skip adding it
- healthCheckCommandInput := c.String("healthcheck-command")
-
- // the user didn't disable the healthcheck but did pass in a healthcheck command
- // now we need to make a healthcheck from the commandline input
- if healthCheckCommandInput != "none" && !c.Bool("no-healthcheck") {
- if len(healthCheckCommandInput) > 0 {
- healthCheck, err = makeHealthCheckFromCli(c)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "unable to create healthcheck")
- }
- } else {
- // the user did not disable the health check and did not pass in a healthcheck
- // command as input. so now we add healthcheck if it exists AND is correct mediatype
- _, mediaType, err := newImage.Manifest(ctx)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "unable to determine mediatype of image %s", newImage.ID())
- }
- if mediaType == manifest.DockerV2Schema2MediaType {
- healthCheck, err = newImage.GetHealthCheck(ctx)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "unable to get healthcheck for %s", c.InputArgs[0])
- }
-
- if healthCheck != nil {
- hcCommand := healthCheck.Test
- if len(hcCommand) < 1 || hcCommand[0] == "" || hcCommand[0] == "NONE" {
- // disable health check
- healthCheck = nil
- } else {
- // apply defaults if image doesn't override them
- if healthCheck.Interval == 0 {
- healthCheck.Interval = 30 * time.Second
- }
- if healthCheck.Timeout == 0 {
- healthCheck.Timeout = 30 * time.Second
- }
- /* Docker default is 0s, so the following would be a no-op
- if healthCheck.StartPeriod == 0 {
- healthCheck.StartPeriod = 0 * time.Second
- }
- */
- if healthCheck.Retries == 0 {
- healthCheck.Retries = 3
- }
- }
- }
- }
- }
- }
- }
-
- createConfig, err := ParseCreateOpts(ctx, c, runtime, imageName, rawImageName, imageData)
- if err != nil {
- return nil, nil, err
- }
-
- // (VR): Ideally we perform the checks _before_ pulling the image but that
- // would require some bigger code refactoring of `ParseCreateOpts` and the
- // logic here. But as the creation code will be consolidated in the future
- // and given auto updates are experimental, we can live with that for now.
- // In the end, the user may only need to correct the policy or the raw image
- // name.
- autoUpdatePolicy, autoUpdatePolicySpecified := createConfig.Labels[autoupdate.Label]
- if autoUpdatePolicySpecified {
- if _, err := autoupdate.LookupPolicy(autoUpdatePolicy); err != nil {
- return nil, nil, err
- }
- // Now we need to make sure we're having a fully-qualified image reference.
- if rootfs != "" {
- return nil, nil, errors.Errorf("auto updates do not work with --rootfs")
- }
- // Make sure the input image is a docker.
- if err := autoupdate.ValidateImageReference(rawImageName); err != nil {
- return nil, nil, err
- }
- }
-
- // Because parseCreateOpts does derive anything from the image, we add health check
- // at this point. The rest is done by WithOptions.
- createConfig.HealthCheck = healthCheck
-
- // TODO: Should be able to return this from ParseCreateOpts
- var pod *libpod.Pod
- if createConfig.Pod != "" {
- pod, err = runtime.LookupPod(createConfig.Pod)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "error looking up pod to join")
- }
- }
-
- ctr, err := CreateContainerFromCreateConfig(ctx, runtime, createConfig, pod)
- if err != nil {
- return nil, nil, err
- }
- if cidFile != nil {
- _, err = cidFile.WriteString(ctr.ID())
- if err != nil {
- logrus.Error(err)
- }
-
- }
-
- logrus.Debugf("New container created %q", ctr.ID())
- return ctr, createConfig, nil
-}
-
-func configureEntrypoint(c *GenericCLIResults, data *inspect.ImageData) []string {
- entrypoint := []string{}
- if c.IsSet("entrypoint") {
- // Force entrypoint to ""
- if c.String("entrypoint") == "" {
- return entrypoint
- }
- // Check if entrypoint specified is json
- if err := json.Unmarshal([]byte(c.String("entrypoint")), &entrypoint); err == nil {
- return entrypoint
- }
- // Return entrypoint as a single command
- return []string{c.String("entrypoint")}
- }
- if data != nil {
- return data.Config.Entrypoint
- }
- return entrypoint
-}
-
-func configurePod(c *GenericCLIResults, runtime *libpod.Runtime, namespaces map[string]string, podName string) (map[string]string, string, error) {
- pod, err := runtime.LookupPod(podName)
- if err != nil {
- return namespaces, "", err
- }
- podInfraID, err := pod.InfraContainerID()
- if err != nil {
- return namespaces, "", err
- }
- hasUserns := false
- if podInfraID != "" {
- podCtr, err := runtime.GetContainer(podInfraID)
- if err != nil {
- return namespaces, "", err
- }
- mappings, err := podCtr.IDMappings()
- if err != nil {
- return namespaces, "", err
- }
- hasUserns = len(mappings.UIDMap) > 0
- }
-
- if (namespaces["pid"] == cc.Pod) || (!c.IsSet("pid") && pod.SharesPID()) {
- namespaces["pid"] = fmt.Sprintf("container:%s", podInfraID)
- }
- if (namespaces["net"] == cc.Pod) || (!c.IsSet("net") && !c.IsSet("network") && pod.SharesNet()) {
- namespaces["net"] = fmt.Sprintf("container:%s", podInfraID)
- }
- if hasUserns && (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) {
- namespaces["user"] = fmt.Sprintf("container:%s", podInfraID)
- }
- if (namespaces["ipc"] == cc.Pod) || (!c.IsSet("ipc") && pod.SharesIPC()) {
- namespaces["ipc"] = fmt.Sprintf("container:%s", podInfraID)
- }
- if (namespaces["uts"] == cc.Pod) || (!c.IsSet("uts") && pod.SharesUTS()) {
- namespaces["uts"] = fmt.Sprintf("container:%s", podInfraID)
- }
- return namespaces, podInfraID, nil
-}
-
-// Parses CLI options related to container creation into a config which can be
-// parsed into an OCI runtime spec
-func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime, imageName string, rawImageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
- var (
- inputCommand, command []string
- memoryLimit, memoryReservation, memorySwap, memoryKernel int64
- blkioWeight uint16
- namespaces map[string]string
- )
-
- idmappings, err := util.ParseIDMapping(ns.UsernsMode(c.String("userns")), c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidname"), c.String("subgidname"))
- if err != nil {
- return nil, err
- }
-
- imageID := ""
-
- inputCommand = c.InputArgs[1:]
- if data != nil {
- imageID = data.ID
- }
-
- rootfs := ""
- if c.Bool("rootfs") {
- rootfs = c.InputArgs[0]
- }
-
- if c.String("memory") != "" {
- memoryLimit, err = units.RAMInBytes(c.String("memory"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory")
- }
- }
- if c.String("memory-reservation") != "" {
- memoryReservation, err = units.RAMInBytes(c.String("memory-reservation"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory-reservation")
- }
- }
- if c.String("memory-swap") != "" {
- if c.String("memory-swap") == "-1" {
- memorySwap = -1
- } else {
- memorySwap, err = units.RAMInBytes(c.String("memory-swap"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory-swap")
- }
- }
- }
- if c.String("kernel-memory") != "" {
- memoryKernel, err = units.RAMInBytes(c.String("kernel-memory"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for kernel-memory")
- }
- }
- if c.String("blkio-weight") != "" {
- u, err := strconv.ParseUint(c.String("blkio-weight"), 10, 16)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for blkio-weight")
- }
- blkioWeight = uint16(u)
- }
-
- tty := c.Bool("tty")
-
- if c.Changed("cpu-period") && c.Changed("cpus") {
- return nil, errors.Errorf("--cpu-period and --cpus cannot be set together")
- }
- if c.Changed("cpu-quota") && c.Changed("cpus") {
- return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together")
- }
-
- if c.Bool("no-hosts") && c.Changed("add-host") {
- return nil, errors.Errorf("--no-hosts and --add-host cannot be set together")
- }
-
- // EXPOSED PORTS
- var portBindings map[nat.Port][]nat.PortBinding
- if data != nil {
- portBindings, err = cc.ExposedPorts(c.StringSlice("expose"), c.StringSlice("publish"), c.Bool("publish-all"), data.Config.ExposedPorts)
- if err != nil {
- return nil, err
- }
- }
-
- // Kernel Namespaces
- // TODO Fix handling of namespace from pod
- // Instead of integrating here, should be done in libpod
- // However, that also involves setting up security opts
- // when the pod's namespace is integrated
- namespaces = map[string]string{
- "cgroup": c.String("cgroupns"),
- "pid": c.String("pid"),
- "net": c.String("network"),
- "ipc": c.String("ipc"),
- "user": c.String("userns"),
- "uts": c.String("uts"),
- }
-
- originalPodName := c.String("pod")
- podName := strings.Replace(originalPodName, "new:", "", 1)
- // after we strip out :new, make sure there is something left for a pod name
- if len(podName) < 1 && c.IsSet("pod") {
- return nil, errors.Errorf("new pod name must be at least one character")
- }
-
- // If we are adding a container to a pod, we would like to add an annotation for the infra ID
- // so kata containers can share VMs inside the pod
- var podInfraID string
- if c.IsSet("pod") {
- if strings.HasPrefix(originalPodName, "new:") {
- // pod does not exist; lets make it
- var podOptions []libpod.PodCreateOption
- podOptions = append(podOptions, libpod.WithPodName(podName), libpod.WithInfraContainer(), libpod.WithPodCgroups())
- if len(portBindings) > 0 {
- ociPortBindings, err := cc.NatToOCIPortBindings(portBindings)
- if err != nil {
- return nil, err
- }
- podOptions = append(podOptions, libpod.WithInfraContainerPorts(ociPortBindings))
- }
-
- podNsOptions, err := GetNamespaceOptions(strings.Split(DefaultKernelNamespaces, ","))
- if err != nil {
- return nil, err
- }
- podOptions = append(podOptions, podNsOptions...)
- // make pod
- pod, err := runtime.NewPod(ctx, podOptions...)
- if err != nil {
- return nil, err
- }
- logrus.Debugf("pod %s created by new container request", pod.ID())
-
- // The container now cannot have port bindings; so we reset the map
- portBindings = make(map[nat.Port][]nat.PortBinding)
- }
- namespaces, podInfraID, err = configurePod(c, runtime, namespaces, podName)
- if err != nil {
- return nil, err
- }
- }
-
- pidMode := ns.PidMode(namespaces["pid"])
- if !cc.Valid(string(pidMode), pidMode) {
- return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
- }
-
- usernsMode := ns.UsernsMode(namespaces["user"])
- if !cc.Valid(string(usernsMode), usernsMode) {
- return nil, errors.Errorf("--userns %q is not valid", namespaces["user"])
- }
-
- utsMode := ns.UTSMode(namespaces["uts"])
- if !cc.Valid(string(utsMode), utsMode) {
- return nil, errors.Errorf("--uts %q is not valid", namespaces["uts"])
- }
-
- cgroupMode := ns.CgroupMode(namespaces["cgroup"])
- if !cgroupMode.Valid() {
- return nil, errors.Errorf("--cgroup %q is not valid", namespaces["cgroup"])
- }
-
- ipcMode := ns.IpcMode(namespaces["ipc"])
- if !cc.Valid(string(ipcMode), ipcMode) {
- return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
- }
-
- // Make sure if network is set to container namespace, port binding is not also being asked for
- netMode := ns.NetworkMode(namespaces["net"])
- if netMode.IsContainer() {
- if len(portBindings) > 0 {
- return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
- }
- }
-
- // USER
- user := c.String("user")
- if user == "" {
- switch {
- case usernsMode.IsKeepID():
- user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID())
- case data == nil:
- user = "0"
- default:
- user = data.Config.User
- }
- }
-
- // STOP SIGNAL
- stopSignal := syscall.SIGTERM
- signalString := ""
- if data != nil {
- signalString = data.Config.StopSignal
- }
- if c.IsSet("stop-signal") {
- signalString = c.String("stop-signal")
- }
- if signalString != "" {
- stopSignal, err = util.ParseSignal(signalString)
- if err != nil {
- return nil, err
- }
- }
-
- // ENVIRONMENT VARIABLES
- //
- // Precedence order (higher index wins):
- // 1) env-host, 2) image data, 3) env-file, 4) env
- env := map[string]string{
- "container": "podman",
- }
-
- // First transform the os env into a map. We need it for the labels later in
- // any case.
- osEnv, err := envLib.ParseSlice(os.Environ())
- if err != nil {
- return nil, errors.Wrap(err, "error parsing host environment variables")
- }
-
- // Start with env-host
-
- if c.Bool("env-host") {
- env = envLib.Join(env, osEnv)
- }
-
- // Image data overrides any previous variables
- if data != nil {
- configEnv, err := envLib.ParseSlice(data.Config.Env)
- if err != nil {
- return nil, errors.Wrap(err, "error passing image environment variables")
- }
- env = envLib.Join(env, configEnv)
- }
-
- // env-file overrides any previous variables
- if c.IsSet("env-file") {
- for _, f := range c.StringSlice("env-file") {
- fileEnv, err := envLib.ParseFile(f)
- if err != nil {
- return nil, err
- }
- // File env is overridden by env.
- env = envLib.Join(env, fileEnv)
- }
- }
-
- if c.IsSet("env") {
- // env overrides any previous variables
- cmdlineEnv := c.StringSlice("env")
- if len(cmdlineEnv) > 0 {
- parsedEnv, err := envLib.ParseSlice(cmdlineEnv)
- if err != nil {
- return nil, err
- }
- env = envLib.Join(env, parsedEnv)
- }
- }
-
- // LABEL VARIABLES
- labels, err := parse.GetAllLabels(c.StringSlice("label-file"), c.StringArray("label"))
- if err != nil {
- return nil, errors.Wrapf(err, "unable to process labels")
- }
- if data != nil {
- for key, val := range data.Config.Labels {
- if _, ok := labels[key]; !ok {
- labels[key] = val
- }
- }
- }
-
- if systemdUnit, exists := osEnv[systemdGen.EnvVariable]; exists {
- labels[systemdGen.EnvVariable] = systemdUnit
- }
-
- // ANNOTATIONS
- annotations := make(map[string]string)
-
- // First, add our default annotations
- annotations[ann.TTY] = "false"
- if tty {
- annotations[ann.TTY] = "true"
- }
-
- // in the event this container is in a pod, and the pod has an infra container
- // we will want to configure it as a type "container" instead defaulting to
- // the behavior of a "sandbox" container
- // In Kata containers:
- // - "sandbox" is the annotation that denotes the container should use its own
- // VM, which is the default behavior
- // - "container" denotes the container should join the VM of the SandboxID
- // (the infra container)
- if podInfraID != "" {
- annotations[ann.SandboxID] = podInfraID
- annotations[ann.ContainerType] = ann.ContainerTypeContainer
- }
-
- if data != nil {
- // Next, add annotations from the image
- for key, value := range data.Annotations {
- annotations[key] = value
- }
- }
- // Last, add user annotations
- for _, annotation := range c.StringSlice("annotation") {
- splitAnnotation := strings.SplitN(annotation, "=", 2)
- if len(splitAnnotation) < 2 {
- return nil, errors.Errorf("Annotations must be formatted KEY=VALUE")
- }
- annotations[splitAnnotation[0]] = splitAnnotation[1]
- }
-
- // WORKING DIRECTORY
- workDir := "/"
- if c.IsSet("workdir") {
- workDir = c.String("workdir")
- } else if data != nil && data.Config.WorkingDir != "" {
- workDir = data.Config.WorkingDir
- }
-
- userCommand := []string{}
- entrypoint := configureEntrypoint(c, data)
- // Build the command
- // If we have an entry point, it goes first
- if len(entrypoint) > 0 {
- command = entrypoint
- }
- if len(inputCommand) > 0 {
- // User command overrides data CMD
- command = append(command, inputCommand...)
- userCommand = append(userCommand, inputCommand...)
- } else if data != nil && len(data.Config.Cmd) > 0 && !c.IsSet("entrypoint") {
- // If not user command, add CMD
- command = append(command, data.Config.Cmd...)
- userCommand = append(userCommand, data.Config.Cmd...)
- }
-
- if data != nil && len(command) == 0 {
- return nil, errors.Errorf("No command specified on command line or as CMD or ENTRYPOINT in this image")
- }
-
- // SHM Size
- shmSize, err := units.FromHumanSize(c.String("shm-size"))
- if err != nil {
- return nil, errors.Wrapf(err, "unable to translate --shm-size")
- }
-
- if c.IsSet("add-host") {
- // Verify the additional hosts are in correct format
- for _, host := range c.StringSlice("add-host") {
- if _, err := parse.ValidateExtraHost(host); err != nil {
- return nil, err
- }
- }
- }
-
- var (
- dnsSearches []string
- dnsServers []string
- dnsOptions []string
- )
- if c.Changed("dns-search") {
- dnsSearches = c.StringSlice("dns-search")
- // Check for explicit dns-search domain of ''
- if len(dnsSearches) == 0 {
- return nil, errors.Errorf("'' is not a valid domain")
- }
- // Validate domains are good
- for _, dom := range dnsSearches {
- if dom == "." {
- if len(dnsSearches) > 1 {
- return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
- }
- continue
- }
- if _, err := parse.ValidateDomain(dom); err != nil {
- return nil, err
- }
- }
- }
- if c.IsSet("dns") {
- dnsServers = append(dnsServers, c.StringSlice("dns")...)
- }
- if c.IsSet("dns-opt") {
- dnsOptions = c.StringSlice("dns-opt")
- }
-
- var ImageVolumes map[string]struct{}
- if data != nil && c.String("image-volume") != "ignore" {
- ImageVolumes = data.Config.Volumes
- }
-
- var imageVolType = map[string]string{
- "bind": "",
- "tmpfs": "",
- "ignore": "",
- }
- if _, ok := imageVolType[c.String("image-volume")]; !ok {
- return nil, errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.String("image-volume"))
- }
-
- systemd := c.String("systemd") == "always"
- if !systemd && command != nil {
- x, err := strconv.ParseBool(c.String("systemd"))
- if err != nil {
- return nil, errors.Wrapf(err, "cannot parse bool %s", c.String("systemd"))
- }
- useSystemdCommands := map[string]bool{
- "/sbin/init": true,
- "/usr/sbin/init": true,
- "/usr/local/sbin/init": true,
- }
- if x && (useSystemdCommands[command[0]] || (filepath.Base(command[0]) == "systemd")) {
- systemd = true
- }
- }
- if systemd {
- if signalString == "" {
- stopSignal, err = util.ParseSignal("RTMIN+3")
- if err != nil {
- return nil, errors.Wrapf(err, "error parsing systemd signal")
- }
- }
- }
- // This is done because cobra cannot have two aliased flags. So we have to check
- // both
- memorySwappiness := c.Int64("memory-swappiness")
-
- logDriver := define.KubernetesLogging
- if c.Changed("log-driver") {
- logDriver = c.String("log-driver")
- }
-
- pidsLimit := c.Int64("pids-limit")
- if c.String("cgroups") == "disabled" && !c.Changed("pids-limit") {
- pidsLimit = -1
- }
-
- pid := &cc.PidConfig{
- PidMode: pidMode,
- }
- ipc := &cc.IpcConfig{
- IpcMode: ipcMode,
- }
-
- cgroup := &cc.CgroupConfig{
- Cgroups: c.String("cgroups"),
- Cgroupns: c.String("cgroupns"),
- CgroupParent: c.String("cgroup-parent"),
- CgroupMode: cgroupMode,
- }
-
- userns := &cc.UserConfig{
- GroupAdd: c.StringSlice("group-add"),
- IDMappings: idmappings,
- UsernsMode: usernsMode,
- User: user,
- }
-
- uts := &cc.UtsConfig{
- UtsMode: utsMode,
- NoHosts: c.Bool("no-hosts"),
- HostAdd: c.StringSlice("add-host"),
- Hostname: c.String("hostname"),
- }
- net := &cc.NetworkConfig{
- DNSOpt: dnsOptions,
- DNSSearch: dnsSearches,
- DNSServers: dnsServers,
- HTTPProxy: c.Bool("http-proxy"),
- MacAddress: c.String("mac-address"),
- Network: c.String("network"),
- NetMode: netMode,
- IPAddress: c.String("ip"),
- Publish: c.StringSlice("publish"),
- PublishAll: c.Bool("publish-all"),
- PortBindings: portBindings,
- }
-
- sysctl := map[string]string{}
- if c.Changed("sysctl") {
- sysctl, err = util.ValidateSysctls(c.StringSlice("sysctl"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for sysctl")
- }
- }
-
- secConfig := &cc.SecurityConfig{
- CapAdd: c.StringSlice("cap-add"),
- CapDrop: c.StringSlice("cap-drop"),
- Privileged: c.Bool("privileged"),
- ReadOnlyRootfs: c.Bool("read-only"),
- ReadOnlyTmpfs: c.Bool("read-only-tmpfs"),
- Sysctl: sysctl,
- }
-
- var securityOpt []string
- if c.Changed("security-opt") {
- securityOpt = c.StringArray("security-opt")
- }
- if err := secConfig.SetSecurityOpts(runtime, securityOpt); err != nil {
- return nil, err
- }
-
- // SECCOMP
- if data != nil {
- if value, exists := labels[seccomp.ContainerImageLabel]; exists {
- secConfig.SeccompProfileFromImage = value
- }
- }
- if policy, err := seccomp.LookupPolicy(c.String("seccomp-policy")); err != nil {
- return nil, err
- } else {
- secConfig.SeccompPolicy = policy
- }
- rtc, err := runtime.GetConfig()
- if err != nil {
- return nil, err
- }
- volumes := rtc.Containers.Volumes
- if c.Changed("volume") {
- volumes = append(volumes, c.StringSlice("volume")...)
- }
-
- devices := rtc.Containers.Devices
- if c.Changed("device") {
- devices = append(devices, c.StringSlice("device")...)
- }
-
- config := &cc.CreateConfig{
- Annotations: annotations,
- BuiltinImgVolumes: ImageVolumes,
- ConmonPidFile: c.String("conmon-pidfile"),
- ImageVolumeType: c.String("image-volume"),
- CidFile: c.String("cidfile"),
- Command: command,
- UserCommand: userCommand,
- Detach: c.Bool("detach"),
- Devices: devices,
- Entrypoint: entrypoint,
- Env: env,
- // ExposedPorts: ports,
- Init: c.Bool("init"),
- InitPath: c.String("init-path"),
- Image: imageName,
- RawImageName: rawImageName,
- ImageID: imageID,
- Interactive: c.Bool("interactive"),
- // IP6Address: c.String("ipv6"), // Not implemented yet - needs CNI support for static v6
- Labels: labels,
- // LinkLocalIP: c.StringSlice("link-local-ip"), // Not implemented yet
- LogDriver: logDriver,
- LogDriverOpt: c.StringSlice("log-opt"),
- Name: c.String("name"),
- // NetworkAlias: c.StringSlice("network-alias"), // Not implemented - does this make sense in Podman?
- Pod: podName,
- Quiet: c.Bool("quiet"),
- Resources: cc.CreateResourceConfig{
- BlkioWeight: blkioWeight,
- BlkioWeightDevice: c.StringSlice("blkio-weight-device"),
- CPUShares: c.Uint64("cpu-shares"),
- CPUPeriod: c.Uint64("cpu-period"),
- CPUsetCPUs: c.String("cpuset-cpus"),
- CPUsetMems: c.String("cpuset-mems"),
- CPUQuota: c.Int64("cpu-quota"),
- CPURtPeriod: c.Uint64("cpu-rt-period"),
- CPURtRuntime: c.Int64("cpu-rt-runtime"),
- CPUs: c.Float64("cpus"),
- DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
- DeviceReadBps: c.StringSlice("device-read-bps"),
- DeviceReadIOps: c.StringSlice("device-read-iops"),
- DeviceWriteBps: c.StringSlice("device-write-bps"),
- DeviceWriteIOps: c.StringSlice("device-write-iops"),
- DisableOomKiller: c.Bool("oom-kill-disable"),
- ShmSize: shmSize,
- Memory: memoryLimit,
- MemoryReservation: memoryReservation,
- MemorySwap: memorySwap,
- MemorySwappiness: int(memorySwappiness),
- KernelMemory: memoryKernel,
- OomScoreAdj: c.Int("oom-score-adj"),
- PidsLimit: pidsLimit,
- Ulimit: c.StringSlice("ulimit"),
- },
- RestartPolicy: c.String("restart"),
- Rm: c.Bool("rm"),
- Security: *secConfig,
- StopSignal: stopSignal,
- StopTimeout: c.Uint("stop-timeout"),
- Systemd: systemd,
- Tmpfs: c.StringArray("tmpfs"),
- Tty: tty,
- MountsFlag: c.StringArray("mount"),
- Volumes: volumes,
- WorkDir: workDir,
- Rootfs: rootfs,
- VolumesFrom: c.StringSlice("volumes-from"),
- Syslog: c.Bool("syslog"),
-
- Pid: *pid,
- Ipc: *ipc,
- Cgroup: *cgroup,
- User: *userns,
- Uts: *uts,
- Network: *net,
- }
-
- warnings, err := verifyContainerResources(config, false)
- if err != nil {
- return nil, err
- }
- for _, warning := range warnings {
- fmt.Fprintln(os.Stderr, warning)
- }
- return config, nil
-}
-
-func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, createConfig *cc.CreateConfig, pod *libpod.Pod) (*libpod.Container, error) {
- runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod)
- if err != nil {
- return nil, err
- }
-
- ctr, err := r.NewContainer(ctx, runtimeSpec, options...)
- if err != nil {
- return nil, err
- }
- return ctr, nil
-}
-
-func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig, error) {
- inCommand := c.String("healthcheck-command")
- inInterval := c.String("healthcheck-interval")
- inRetries := c.Uint("healthcheck-retries")
- inTimeout := c.String("healthcheck-timeout")
- inStartPeriod := c.String("healthcheck-start-period")
-
- // Every healthcheck requires a command
- if len(inCommand) == 0 {
- return nil, errors.New("Must define a healthcheck command for all healthchecks")
- }
-
- // first try to parse option value as JSON array of strings...
- cmd := []string{}
- err := json.Unmarshal([]byte(inCommand), &cmd)
- if err != nil {
- // ...otherwise pass it to "/bin/sh -c" inside the container
- cmd = []string{"CMD-SHELL", inCommand}
- }
- hc := manifest.Schema2HealthConfig{
- Test: cmd,
- }
-
- if inInterval == "disable" {
- inInterval = "0"
- }
- intervalDuration, err := time.ParseDuration(inInterval)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid healthcheck-interval %s ", inInterval)
- }
-
- hc.Interval = intervalDuration
-
- if inRetries < 1 {
- return nil, errors.New("healthcheck-retries must be greater than 0.")
- }
- hc.Retries = int(inRetries)
- timeoutDuration, err := time.ParseDuration(inTimeout)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", inTimeout)
- }
- if timeoutDuration < time.Duration(1) {
- return nil, errors.New("healthcheck-timeout must be at least 1 second")
- }
- hc.Timeout = timeoutDuration
-
- startPeriodDuration, err := time.ParseDuration(inStartPeriod)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid healthcheck-start-period %s", inStartPeriod)
- }
- if startPeriodDuration < time.Duration(0) {
- return nil, errors.New("healthcheck-start-period must be 0 seconds or greater")
- }
- hc.StartPeriod = startPeriodDuration
-
- return &hc, nil
-}
-
-// GetNamespaceOptions transforms a slice of kernel namespaces
-// into a slice of pod create options. Currently, not all
-// kernel namespaces are supported, and they will be returned in an error
-func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) {
- var options []libpod.PodCreateOption
- var erroredOptions []libpod.PodCreateOption
- for _, toShare := range ns {
- switch toShare {
- case "cgroup":
- options = append(options, libpod.WithPodCgroups())
- case "net":
- options = append(options, libpod.WithPodNet())
- case "mnt":
- return erroredOptions, errors.Errorf("Mount sharing functionality not supported on pod level")
- case "pid":
- options = append(options, libpod.WithPodPID())
- case "user":
- return erroredOptions, errors.Errorf("User sharing functionality not supported on pod level")
- case "ipc":
- options = append(options, libpod.WithPodIPC())
- case "uts":
- options = append(options, libpod.WithPodUTS())
- case "":
- case "none":
- return erroredOptions, nil
- default:
- return erroredOptions, errors.Errorf("Invalid kernel namespace to share: %s. Options are: net, pid, ipc, uts or none", toShare)
- }
- }
- return options, nil
-}
-
-func addWarning(warnings []string, msg string) []string {
- logrus.Warn(msg)
- return append(warnings, msg)
-}
-
-func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) {
- warnings := []string{}
-
- cgroup2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil || cgroup2 {
- return warnings, err
- }
-
- sysInfo := sysinfo.New(true)
-
- // memory subsystem checks and adjustments
- if config.Resources.Memory > 0 && !sysInfo.MemoryLimit {
- warnings = addWarning(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
- config.Resources.Memory = 0
- config.Resources.MemorySwap = -1
- }
- if config.Resources.Memory > 0 && config.Resources.MemorySwap != -1 && !sysInfo.SwapLimit {
- warnings = addWarning(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
- config.Resources.MemorySwap = -1
- }
- if config.Resources.Memory > 0 && config.Resources.MemorySwap > 0 && config.Resources.MemorySwap < config.Resources.Memory {
- return warnings, fmt.Errorf("minimum memoryswap limit should be larger than memory limit, see usage")
- }
- if config.Resources.Memory == 0 && config.Resources.MemorySwap > 0 && !update {
- return warnings, fmt.Errorf("you should always set the memory limit when using memoryswap limit, see usage")
- }
- if config.Resources.MemorySwappiness != -1 {
- if !sysInfo.MemorySwappiness {
- msg := "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded."
- warnings = addWarning(warnings, msg)
- config.Resources.MemorySwappiness = -1
- } else {
- swappiness := config.Resources.MemorySwappiness
- if swappiness < -1 || swappiness > 100 {
- return warnings, fmt.Errorf("invalid value: %v, valid memory swappiness range is 0-100", swappiness)
- }
- }
- }
- if config.Resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
- warnings = addWarning(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
- config.Resources.MemoryReservation = 0
- }
- if config.Resources.Memory > 0 && config.Resources.MemoryReservation > 0 && config.Resources.Memory < config.Resources.MemoryReservation {
- return warnings, fmt.Errorf("minimum memory limit cannot be less than memory reservation limit, see usage")
- }
- if config.Resources.KernelMemory > 0 && !sysInfo.KernelMemory {
- warnings = addWarning(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
- config.Resources.KernelMemory = 0
- }
- if config.Resources.DisableOomKiller && !sysInfo.OomKillDisable {
- // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
- // warning the caller if they already wanted the feature to be off
- warnings = addWarning(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
- config.Resources.DisableOomKiller = false
- }
-
- if config.Resources.PidsLimit != 0 && !sysInfo.PidsLimit {
- warnings = addWarning(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
- config.Resources.PidsLimit = 0
- }
-
- if config.Resources.CPUShares > 0 && !sysInfo.CPUShares {
- warnings = addWarning(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
- config.Resources.CPUShares = 0
- }
- if config.Resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
- warnings = addWarning(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
- config.Resources.CPUPeriod = 0
- }
- if config.Resources.CPUPeriod != 0 && (config.Resources.CPUPeriod < 1000 || config.Resources.CPUPeriod > 1000000) {
- return warnings, fmt.Errorf("CPU cfs period cannot be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
- }
- if config.Resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
- warnings = addWarning(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
- config.Resources.CPUQuota = 0
- }
- if config.Resources.CPUQuota > 0 && config.Resources.CPUQuota < 1000 {
- return warnings, fmt.Errorf("CPU cfs quota cannot be less than 1ms (i.e. 1000)")
- }
- // cpuset subsystem checks and adjustments
- if (config.Resources.CPUsetCPUs != "" || config.Resources.CPUsetMems != "") && !sysInfo.Cpuset {
- warnings = addWarning(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. CPUset discarded.")
- config.Resources.CPUsetCPUs = ""
- config.Resources.CPUsetMems = ""
- }
- cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(config.Resources.CPUsetCPUs)
- if err != nil {
- return warnings, fmt.Errorf("invalid value %s for cpuset cpus", config.Resources.CPUsetCPUs)
- }
- if !cpusAvailable {
- return warnings, fmt.Errorf("requested CPUs are not available - requested %s, available: %s", config.Resources.CPUsetCPUs, sysInfo.Cpus)
- }
- memsAvailable, err := sysInfo.IsCpusetMemsAvailable(config.Resources.CPUsetMems)
- if err != nil {
- return warnings, fmt.Errorf("invalid value %s for cpuset mems", config.Resources.CPUsetMems)
- }
- if !memsAvailable {
- return warnings, fmt.Errorf("requested memory nodes are not available - requested %s, available: %s", config.Resources.CPUsetMems, sysInfo.Mems)
- }
-
- // blkio subsystem checks and adjustments
- if config.Resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
- warnings = addWarning(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
- config.Resources.BlkioWeight = 0
- }
- if config.Resources.BlkioWeight > 0 && (config.Resources.BlkioWeight < 10 || config.Resources.BlkioWeight > 1000) {
- return warnings, fmt.Errorf("range of blkio weight is from 10 to 1000")
- }
- if len(config.Resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
- warnings = addWarning(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
- config.Resources.BlkioWeightDevice = []string{}
- }
- if len(config.Resources.DeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded")
- config.Resources.DeviceReadBps = []string{}
- }
- if len(config.Resources.DeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
- config.Resources.DeviceWriteBps = []string{}
- }
- if len(config.Resources.DeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
- config.Resources.DeviceReadIOps = []string{}
- }
- if len(config.Resources.DeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
- config.Resources.DeviceWriteIOps = []string{}
- }
-
- return warnings, nil
-}
diff --git a/pkg/varlinkapi/events.go b/pkg/varlinkapi/events.go
deleted file mode 100644
index 8628b1ce6..000000000
--- a/pkg/varlinkapi/events.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "context"
- "time"
-
- "github.com/containers/podman/v2/libpod/events"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
-)
-
-// GetEvents is a remote endpoint to get events from the event log
-func (i *VarlinkAPI) GetEvents(call iopodman.VarlinkCall, filter []string, since string, until string) error {
- var (
- fromStart bool
- eventsError error
- event *events.Event
- stream bool
- )
- if call.WantsMore() {
- stream = true
- call.Continues = true
- }
- if len(since) > 0 || len(until) > 0 {
- fromStart = true
- }
- eventChannel := make(chan *events.Event)
- go func() {
- readOpts := events.ReadOptions{FromStart: fromStart, Stream: stream, Filters: filter, EventChannel: eventChannel}
- eventsError = i.Runtime.Events(context.Background(), readOpts)
- }()
- if eventsError != nil {
- return call.ReplyErrorOccurred(eventsError.Error())
- }
- for {
- event = <-eventChannel
- if event == nil {
- call.Continues = false
- break
- }
- call.ReplyGetEvents(iopodman.Event{
- Id: event.ID,
- Image: event.Image,
- Name: event.Name,
- Status: string(event.Status),
- Time: event.Time.Format(time.RFC3339Nano),
- Type: string(event.Type),
- })
- if !call.Continues {
- // For a one-shot on events, we break out here
- break
- }
- }
- return nil
-}
diff --git a/pkg/varlinkapi/funcs.go b/pkg/varlinkapi/funcs.go
deleted file mode 100644
index 8fb8a7ea0..000000000
--- a/pkg/varlinkapi/funcs.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package varlinkapi
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/containers/image/v5/types"
- "github.com/containers/podman/v2/libpod/image"
- "github.com/google/shlex"
- "github.com/pkg/errors"
-)
-
-func GetSystemContext(authfile string) (*types.SystemContext, error) {
- if authfile != "" {
- if _, err := os.Stat(authfile); err != nil {
- return nil, errors.Wrapf(err, "error checking authfile path %s", authfile)
- }
- }
- return image.GetSystemContext("", authfile, false), nil
-}
-
-func substituteCommand(cmd string) (string, error) {
- var (
- newCommand string
- )
-
- // Replace cmd with "/proc/self/exe" if "podman" or "docker" is being
- // used. If "/usr/bin/docker" is provided, we also sub in podman.
- // Otherwise, leave the command unchanged.
- if cmd == "podman" || filepath.Base(cmd) == "docker" {
- newCommand = "/proc/self/exe"
- } else {
- newCommand = cmd
- }
-
- // If cmd is an absolute or relative path, check if the file exists.
- // Throw an error if it doesn't exist.
- if strings.Contains(newCommand, "/") || strings.HasPrefix(newCommand, ".") {
- res, err := filepath.Abs(newCommand)
- if err != nil {
- return "", err
- }
- if _, err := os.Stat(res); !os.IsNotExist(err) {
- return res, nil
- } else if err != nil {
- return "", err
- }
- }
-
- return newCommand, nil
-}
-
-// GenerateCommand takes a label (string) and converts it to an executable command
-func GenerateCommand(command, imageName, name, globalOpts string) ([]string, error) {
- var (
- newCommand []string
- )
- if name == "" {
- name = imageName
- }
-
- cmd, err := shlex.Split(command)
- if err != nil {
- return nil, err
- }
-
- prog, err := substituteCommand(cmd[0])
- if err != nil {
- return nil, err
- }
- newCommand = append(newCommand, prog)
-
- for _, arg := range cmd[1:] {
- var newArg string
- switch arg {
- case "IMAGE":
- newArg = imageName
- case "$IMAGE":
- newArg = imageName
- case "IMAGE=IMAGE":
- newArg = fmt.Sprintf("IMAGE=%s", imageName)
- case "IMAGE=$IMAGE":
- newArg = fmt.Sprintf("IMAGE=%s", imageName)
- case "NAME":
- newArg = name
- case "NAME=NAME":
- newArg = fmt.Sprintf("NAME=%s", name)
- case "NAME=$NAME":
- newArg = fmt.Sprintf("NAME=%s", name)
- case "$NAME":
- newArg = name
- case "$GLOBAL_OPTS":
- newArg = globalOpts
- default:
- newArg = arg
- }
- newCommand = append(newCommand, newArg)
- }
- return newCommand, nil
-}
-
-// GenerateRunEnvironment merges the current environment variables with optional
-// environment variables provided by the user
-func GenerateRunEnvironment(name, imageName string, opts map[string]string) []string {
- newEnv := os.Environ()
- newEnv = append(newEnv, fmt.Sprintf("NAME=%s", name))
- newEnv = append(newEnv, fmt.Sprintf("IMAGE=%s", imageName))
-
- if opts["opt1"] != "" {
- newEnv = append(newEnv, fmt.Sprintf("OPT1=%s", opts["opt1"]))
- }
- if opts["opt2"] != "" {
- newEnv = append(newEnv, fmt.Sprintf("OPT2=%s", opts["opt2"]))
- }
- if opts["opt3"] != "" {
- newEnv = append(newEnv, fmt.Sprintf("OPT3=%s", opts["opt3"]))
- }
- return newEnv
-}
diff --git a/pkg/varlinkapi/generate.go b/pkg/varlinkapi/generate.go
deleted file mode 100644
index bbc16dae5..000000000
--- a/pkg/varlinkapi/generate.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "encoding/json"
-
- iopodman "github.com/containers/podman/v2/pkg/varlink"
-)
-
-// GenerateKube ...
-func (i *VarlinkAPI) GenerateKube(call iopodman.VarlinkCall, name string, service bool) error {
- pod, serv, err := GenerateKube(name, service, i.Runtime)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- podB, err := json.Marshal(pod)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- servB, err := json.Marshal(serv)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- return call.ReplyGenerateKube(iopodman.KubePodService{
- Pod: string(podB),
- Service: string(servB),
- })
-}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
deleted file mode 100644
index af6c43fec..000000000
--- a/pkg/varlinkapi/images.go
+++ /dev/null
@@ -1,1037 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/containers/buildah"
- "github.com/containers/buildah/imagebuildah"
- dockerarchive "github.com/containers/image/v5/docker/archive"
- "github.com/containers/image/v5/manifest"
- "github.com/containers/image/v5/transports/alltransports"
- "github.com/containers/image/v5/types"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/libpod/image"
- "github.com/containers/podman/v2/pkg/channel"
- "github.com/containers/podman/v2/pkg/util"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/containers/podman/v2/utils"
- "github.com/containers/storage/pkg/archive"
- v1 "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// ListImagesWithFilters returns a list of images that have been filtered
-func (i *VarlinkAPI) ListImagesWithFilters(call iopodman.VarlinkCall, filters []string) error {
- images, err := i.Runtime.ImageRuntime().GetImagesWithFilters(filters)
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err))
- }
- imageList, err := imagesToImageList(images)
- if err != nil {
- return call.ReplyErrorOccurred("unable to parse response " + err.Error())
- }
- return call.ReplyListImagesWithFilters(imageList)
-}
-
-// imagesToImageList converts a slice of Images to an imagelist for varlink responses
-func imagesToImageList(images []*image.Image) ([]iopodman.Image, error) {
- var imageList []iopodman.Image
- for _, img := range images {
- labels, _ := img.Labels(getContext())
- containers, _ := img.Containers()
- repoDigests, err := img.RepoDigests()
- if err != nil {
- return nil, err
- }
-
- size, _ := img.Size(getContext())
- isParent, err := img.IsParent(context.TODO())
- if err != nil {
- return nil, err
- }
-
- i := iopodman.Image{
- Id: img.ID(),
- Digest: string(img.Digest()),
- ParentId: img.Parent,
- RepoTags: img.Names(),
- RepoDigests: repoDigests,
- Created: img.Created().Format(time.RFC3339),
- Size: int64(*size),
- VirtualSize: img.VirtualSize,
- Containers: int64(len(containers)),
- Labels: labels,
- IsParent: isParent,
- ReadOnly: img.IsReadOnly(),
- History: img.NamesHistory(),
- }
- imageList = append(imageList, i)
- }
- return imageList, nil
-}
-
-// ListImages lists all the images in the store
-// It requires no inputs.
-func (i *VarlinkAPI) ListImages(call iopodman.VarlinkCall) error {
- images, err := i.Runtime.ImageRuntime().GetImages()
- if err != nil {
- return call.ReplyErrorOccurred("unable to get list of images " + err.Error())
- }
- imageList, err := imagesToImageList(images)
- if err != nil {
- return call.ReplyErrorOccurred("unable to parse response " + err.Error())
- }
- return call.ReplyListImages(imageList)
-}
-
-// GetImage returns a single image in the form of a Image
-func (i *VarlinkAPI) GetImage(call iopodman.VarlinkCall, id string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id)
- if err != nil {
- return call.ReplyImageNotFound(id, err.Error())
- }
- labels, err := newImage.Labels(getContext())
- if err != nil {
- return err
- }
- containers, err := newImage.Containers()
- if err != nil {
- return err
- }
- repoDigests, err := newImage.RepoDigests()
- if err != nil {
- return err
- }
- size, err := newImage.Size(getContext())
- if err != nil {
- return err
- }
-
- il := iopodman.Image{
- Id: newImage.ID(),
- ParentId: newImage.Parent,
- RepoTags: newImage.Names(),
- RepoDigests: repoDigests,
- Created: newImage.Created().Format(time.RFC3339),
- Size: int64(*size),
- VirtualSize: newImage.VirtualSize,
- Containers: int64(len(containers)),
- Labels: labels,
- TopLayer: newImage.TopLayer(),
- ReadOnly: newImage.IsReadOnly(),
- History: newImage.NamesHistory(),
- }
- return call.ReplyGetImage(il)
-}
-
-// BuildImage ...
-func (i *VarlinkAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildInfo) error {
- var (
- namespace []buildah.NamespaceOption
- imageID string
- err error
- )
-
- contextDir := config.ContextDir
-
- newContextDir, err := ioutil.TempDir("", "buildTarball")
- if err != nil {
- call.ReplyErrorOccurred("unable to create tempdir")
- }
- logrus.Debugf("created new context dir at %s", newContextDir)
-
- reader, err := os.Open(contextDir)
- if err != nil {
- logrus.Errorf("failed to open the context dir tar file")
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to open context dir tar file %s", contextDir))
- }
- defer reader.Close()
- if err := archive.Untar(reader, newContextDir, &archive.TarOptions{}); err != nil {
- logrus.Errorf("fail to untar the context dir tarball (%s) to the context dir (%s)", contextDir, newContextDir)
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to untar context dir %s", contextDir))
- }
- logrus.Debugf("untar of %s successful", contextDir)
- defer func() {
- if err := os.Remove(contextDir); err != nil {
- logrus.Error(err)
- }
- if err := os.RemoveAll(newContextDir); err != nil {
- logrus.Errorf("unable to delete directory '%s': %q", newContextDir, err)
- }
- }()
-
- systemContext := types.SystemContext{}
- // All output (stdout, stderr) is captured in output as well
- var output bytes.Buffer
-
- commonOpts := &buildah.CommonBuildOptions{
- AddHost: config.BuildOptions.AddHosts,
- CgroupParent: config.BuildOptions.CgroupParent,
- CPUPeriod: uint64(config.BuildOptions.CpuPeriod),
- CPUQuota: config.BuildOptions.CpuQuota,
- CPUSetCPUs: config.BuildOptions.CpusetCpus,
- CPUSetMems: config.BuildOptions.CpusetMems,
- Memory: config.BuildOptions.Memory,
- MemorySwap: config.BuildOptions.MemorySwap,
- ShmSize: config.BuildOptions.ShmSize,
- Ulimit: config.BuildOptions.Ulimit,
- Volumes: config.BuildOptions.Volume,
- }
-
- options := imagebuildah.BuildOptions{
- AddCapabilities: config.AddCapabilities,
- AdditionalTags: config.AdditionalTags,
- Annotations: config.Annotations,
- Architecture: config.Architecture,
- Args: config.BuildArgs,
- CNIConfigDir: config.CniConfigDir,
- CNIPluginPath: config.CniPluginDir,
- CommonBuildOpts: commonOpts,
- Compression: stringCompressionToArchiveType(config.Compression),
- ContextDirectory: newContextDir,
- DefaultMountsFilePath: config.DefaultsMountFilePath,
- Devices: config.Devices,
- Err: &output,
- ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs,
- IIDFile: config.Iidfile,
- Labels: config.Label,
- Layers: config.Layers,
- NamespaceOptions: namespace,
- NoCache: config.Nocache,
- OS: config.Os,
- Out: &output,
- Output: config.Output,
- OutputFormat: config.OutputFormat,
- PullPolicy: stringPullPolicyToType(config.PullPolicy),
- Quiet: config.Quiet,
- RemoveIntermediateCtrs: config.RemoteIntermediateCtrs,
- ReportWriter: &output,
- RuntimeArgs: config.RuntimeArgs,
- SignBy: config.SignBy,
- Squash: config.Squash,
- SystemContext: &systemContext,
- Target: config.Target,
- TransientMounts: config.TransientMounts,
- }
-
- if call.WantsMore() {
- call.Continues = true
- } else {
- return call.ReplyErrorOccurred("endpoint requires a more connection")
- }
-
- var newPathDockerFiles []string
-
- for _, d := range config.Dockerfiles {
- if strings.HasPrefix(d, "http://") ||
- strings.HasPrefix(d, "https://") ||
- strings.HasPrefix(d, "git://") ||
- strings.HasPrefix(d, "github.com/") {
- newPathDockerFiles = append(newPathDockerFiles, d)
- continue
- }
- base := filepath.Base(d)
- newPathDockerFiles = append(newPathDockerFiles, filepath.Join(newContextDir, base))
- }
-
- c := make(chan error)
- go func() {
- iid, _, err := i.Runtime.Build(getContext(), options, newPathDockerFiles...)
- imageID = iid
- c <- err
- close(c)
- }()
-
- var log []string
- done := false
- for {
- outputLine, err := output.ReadString('\n')
- if err == nil {
- log = append(log, outputLine)
- if call.WantsMore() {
- // we want to reply with what we have
- br := iopodman.MoreResponse{
- Logs: log,
- }
- call.ReplyBuildImage(br)
- log = []string{}
- }
- continue
- } else if err == io.EOF {
- select {
- case err := <-c:
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- done = true
- default:
- if call.WantsMore() {
- time.Sleep(1 * time.Second)
- break
- }
- }
- } else {
- return call.ReplyErrorOccurred(err.Error())
- }
- if done {
- break
- }
- }
- call.Continues = false
-
- br := iopodman.MoreResponse{
- Logs: log,
- Id: imageID,
- }
- return call.ReplyBuildImage(br)
-}
-
-// InspectImage returns an image's inspect information as a string that can be serialized.
-// Requires an image ID or name
-func (i *VarlinkAPI) InspectImage(call iopodman.VarlinkCall, name string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- inspectInfo, err := newImage.Inspect(getContext())
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- b, err := json.Marshal(inspectInfo)
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to serialize"))
- }
- return call.ReplyInspectImage(string(b))
-}
-
-// HistoryImage returns the history of the image's layers
-// Requires an image or name
-func (i *VarlinkAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- history, err := newImage.History(getContext())
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- var histories []iopodman.ImageHistory
- for _, hist := range history {
- imageHistory := iopodman.ImageHistory{
- Id: hist.ID,
- Created: hist.Created.Format(time.RFC3339),
- CreatedBy: hist.CreatedBy,
- Tags: newImage.Names(),
- Size: hist.Size,
- Comment: hist.Comment,
- }
- histories = append(histories, imageHistory)
- }
- return call.ReplyHistoryImage(histories)
-}
-
-// PushImage pushes an local image to registry
-func (i *VarlinkAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compress bool, format string, removeSignatures bool, signBy string) error {
- var (
- manifestType string
- )
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- destname := name
- if tag != "" {
- destname = tag
- }
- dockerRegistryOptions := image.DockerRegistryOptions{}
- if format != "" {
- switch format {
- case "oci": // nolint
- manifestType = v1.MediaTypeImageManifest
- case "v2s1":
- manifestType = manifest.DockerV2Schema1SignedMediaType
- case "v2s2", "docker":
- manifestType = manifest.DockerV2Schema2MediaType
- default:
- return call.ReplyErrorOccurred(fmt.Sprintf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", format))
- }
- }
- so := image.SigningOptions{
- RemoveSignatures: removeSignatures,
- SignBy: signBy,
- }
-
- if call.WantsMore() {
- call.Continues = true
- }
-
- output := bytes.NewBuffer([]byte{})
- c := make(chan error)
- go func() {
- writer := bytes.NewBuffer([]byte{})
- err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", "", writer, compress, so, &dockerRegistryOptions, nil)
- if err != nil {
- c <- err
- }
- _, err = io.CopyBuffer(output, writer, nil)
- c <- err
- close(c)
- }()
-
- // TODO When pull output gets fixed for the remote client, we need to look into how we can turn below
- // into something re-usable. it is in build too
- var log []string
- done := false
- for {
- line, err := output.ReadString('\n')
- if err == nil {
- log = append(log, line)
- continue
- } else if err == io.EOF {
- select {
- case err := <-c:
- if err != nil {
- logrus.Errorf("reading of output during push failed for %s", newImage.ID())
- return call.ReplyErrorOccurred(err.Error())
- }
- done = true
- default:
- if !call.WantsMore() {
- break
- }
- br := iopodman.MoreResponse{
- Logs: log,
- Id: newImage.ID(),
- }
- call.ReplyPushImage(br)
- log = []string{}
- }
- } else {
- return call.ReplyErrorOccurred(err.Error())
- }
- if done {
- break
- }
- }
- call.Continues = false
-
- br := iopodman.MoreResponse{
- Logs: log,
- Id: newImage.ID(),
- }
- return call.ReplyPushImage(br)
-}
-
-// TagImage accepts an image name and tag as strings and tags an image in the local store.
-func (i *VarlinkAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- if err := newImage.TagImage(tag); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyTagImage(newImage.ID())
-}
-
-// UntagImage accepts an image name and tag as strings and removes the tag from the local store.
-func (i *VarlinkAPI) UntagImage(call iopodman.VarlinkCall, name, tag string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- if err := newImage.UntagImage(tag); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyUntagImage(newImage.ID())
-}
-
-// RemoveImage accepts a image name or ID as a string and force bool to determine if it should
-// remove the image even if being used by stopped containers
-func (i *VarlinkAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bool) error {
- ctx := getContext()
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- _, err = i.Runtime.RemoveImage(ctx, newImage, force)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyRemoveImage(newImage.ID())
-}
-
-// RemoveImageWithResponse accepts an image name and force bool. It returns details about what
-// was done in removeimageresponse struct.
-func (i *VarlinkAPI) RemoveImageWithResponse(call iopodman.VarlinkCall, name string, force bool) error {
- ir := iopodman.RemoveImageResponse{}
- ctx := getContext()
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
- response, err := i.Runtime.RemoveImage(ctx, newImage, force)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- ir.Untagged = append(ir.Untagged, response.Untagged...)
- ir.Deleted = response.Deleted
- return call.ReplyRemoveImageWithResponse(ir)
-}
-
-// SearchImages searches all registries configured in /etc/containers/registries.conf for an image
-// Requires an image name and a search limit as int
-func (i *VarlinkAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64, filter iopodman.ImageSearchFilter) error {
- // Transform all arguments to proper types first
- argLimit := 0
- argIsOfficial := types.OptionalBoolUndefined
- argIsAutomated := types.OptionalBoolUndefined
- if limit != nil {
- argLimit = int(*limit)
- }
- if filter.Is_official != nil {
- argIsOfficial = types.NewOptionalBool(*filter.Is_official)
- }
- if filter.Is_automated != nil {
- argIsAutomated = types.NewOptionalBool(*filter.Is_automated)
- }
-
- // Transform a SearchFilter the backend can deal with
- sFilter := image.SearchFilter{
- IsOfficial: argIsOfficial,
- IsAutomated: argIsAutomated,
- Stars: int(filter.Star_count),
- }
-
- searchOptions := image.SearchOptions{
- Limit: argLimit,
- Filter: sFilter,
- }
- results, err := image.SearchImages(query, searchOptions)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- var imageResults []iopodman.ImageSearchResult
- for _, result := range results {
- i := iopodman.ImageSearchResult{
- Registry: result.Index,
- Description: result.Description,
- Is_official: result.Official == "[OK]",
- Is_automated: result.Automated == "[OK]",
- Name: result.Name,
- Star_count: int64(result.Stars),
- }
- imageResults = append(imageResults, i)
- }
- return call.ReplySearchImages(imageResults)
-}
-
-// DeleteUnusedImages deletes any images that do not have containers associated with it.
-// TODO Filters are not implemented
-func (i *VarlinkAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error {
- images, err := i.Runtime.ImageRuntime().GetImages()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- var deletedImages []string
- for _, img := range images {
- containers, err := img.Containers()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if len(containers) == 0 {
- if err := img.Remove(context.TODO(), false); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- deletedImages = append(deletedImages, img.ID())
- }
- }
- return call.ReplyDeleteUnusedImages(deletedImages)
-}
-
-// Commit ...
-func (i *VarlinkAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error {
- var (
- newImage *image.Image
- log []string
- mimeType string
- )
- output := channel.NewWriter(make(chan []byte))
- channelClose := func() {
- if err := output.Close(); err != nil {
- logrus.Errorf("failed to close channel writer: %q", err)
- }
- }
- defer channelClose()
-
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyContainerNotFound(name, err.Error())
- }
- rtc, err := i.Runtime.GetConfig()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
- switch manifestType {
- case "oci", "": // nolint
- mimeType = buildah.OCIv1ImageManifest
- case "docker":
- mimeType = manifest.DockerV2Schema2MediaType
- default:
- return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image format %q", manifestType))
- }
- coptions := buildah.CommitOptions{
- SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
- ReportWriter: output,
- SystemContext: sc,
- PreferredManifestType: mimeType,
- }
- options := libpod.ContainerCommitOptions{
- CommitOptions: coptions,
- Pause: pause,
- Message: message,
- Changes: changes,
- Author: author,
- }
-
- if call.WantsMore() {
- call.Continues = true
- }
-
- c := make(chan error)
-
- go func() {
- newImage, err = ctr.Commit(getContext(), imageName, options)
- if err != nil {
- c <- err
- }
- c <- nil
- close(c)
- }()
-
- // reply is the func being sent to the output forwarder. in this case it is replying
- // with a more response struct
- reply := func(br iopodman.MoreResponse) error {
- return call.ReplyCommit(br)
- }
- log, err = forwardOutput(log, c, call.WantsMore(), output, reply)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- call.Continues = false
- br := iopodman.MoreResponse{
- Logs: log,
- Id: newImage.ID(),
- }
- return call.ReplyCommit(br)
-}
-
-// ImportImage imports an image from a tarball to the image store
-func (i *VarlinkAPI) ImportImage(call iopodman.VarlinkCall, source, reference, message string, changes []string, delete bool) error {
- configChanges, err := util.GetImageConfig(changes)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- history := []v1.History{
- {Comment: message},
- }
- config := v1.Image{
- Config: configChanges.ImageConfig,
- History: history,
- }
- newImage, err := i.Runtime.ImageRuntime().Import(getContext(), source, reference, nil, image.SigningOptions{}, config)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if delete {
- if err := os.Remove(source); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- }
-
- return call.ReplyImportImage(newImage.ID())
-}
-
-// ExportImage exports an image to the provided destination
-// destination must have the transport type!!
-func (i *VarlinkAPI) ExportImage(call iopodman.VarlinkCall, name, destination string, compress bool, tags []string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyImageNotFound(name, err.Error())
- }
-
- additionalTags, err := image.GetAdditionalTags(tags)
- if err != nil {
- return err
- }
-
- if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyExportImage(newImage.ID())
-}
-
-// PullImage pulls an image from a registry to the image store.
-func (i *VarlinkAPI) PullImage(call iopodman.VarlinkCall, name string, creds iopodman.AuthConfig) error {
- var (
- imageID string
- err error
- )
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: &types.DockerAuthConfig{
- Username: creds.Username,
- Password: creds.Password,
- },
- }
-
- so := image.SigningOptions{}
-
- if call.WantsMore() {
- call.Continues = true
- }
- output := channel.NewWriter(make(chan []byte))
- channelClose := func() {
- if err := output.Close(); err != nil {
- logrus.Errorf("failed to close channel writer: %q", err)
- }
- }
- defer channelClose()
- c := make(chan error)
- defer close(c)
-
- go func() {
- var foundError bool
- if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
- srcRef, err := alltransports.ParseImageName(name)
- if err != nil {
- c <- errors.Wrapf(err, "error parsing %q", name)
- }
- newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, "", output)
- if err != nil {
- foundError = true
- c <- errors.Wrapf(err, "error pulling image from %q", name)
- } else {
- imageID = newImage[0].ID()
- }
- } else {
- newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", output, &dockerRegistryOptions, so, nil, util.PullImageMissing)
- if err != nil {
- foundError = true
- c <- errors.Wrapf(err, "unable to pull %s", name)
- } else {
- imageID = newImage.ID()
- }
- }
- if !foundError {
- c <- nil
- }
- }()
-
- var log []string
- reply := func(br iopodman.MoreResponse) error {
- return call.ReplyPullImage(br)
- }
- log, err = forwardOutput(log, c, call.WantsMore(), output, reply)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- call.Continues = false
- br := iopodman.MoreResponse{
- Logs: log,
- Id: imageID,
- }
- return call.ReplyPullImage(br)
-}
-
-// ImageExists returns bool as to whether the input image exists in local storage
-func (i *VarlinkAPI) ImageExists(call iopodman.VarlinkCall, name string) error {
- _, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if errors.Cause(err) == image.ErrNoSuchImage {
- return call.ReplyImageExists(1)
- }
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyImageExists(0)
-}
-
-// ContainerRunlabel ...
-func (i *VarlinkAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.Runlabel) error {
- ctx := getContext()
- dockerRegistryOptions := image.DockerRegistryOptions{}
- stdErr := os.Stderr
- stdOut := os.Stdout
- stdIn := os.Stdin
-
- runLabel, imageName, err := GetRunlabel(input.Label, input.Image, ctx, i.Runtime, input.Pull, "", dockerRegistryOptions, input.Authfile, "", nil)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if runLabel == "" {
- return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label))
- }
-
- cmd, env, err := GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs, "")
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if err := utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyContainerRunlabel()
-}
-
-// ImagesPrune ....
-func (i *VarlinkAPI) ImagesPrune(call iopodman.VarlinkCall, all bool, filter []string) error {
- prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all, []string{})
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyImagesPrune(prunedImages)
-}
-
-// ImageSave ....
-func (i *VarlinkAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageSaveOptions) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(options.Name)
- if err != nil {
- if errors.Cause(err) == define.ErrNoSuchImage {
- return call.ReplyImageNotFound(options.Name, err.Error())
- }
- return call.ReplyErrorOccurred(err.Error())
- }
-
- // Determine if we are dealing with a tarball or dir
- var output string
- outputToDir := false
- if options.Format == "oci-archive" || options.Format == "docker-archive" {
- tempfile, err := ioutil.TempFile("", "varlink_send")
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- output = tempfile.Name()
- tempfile.Close()
- } else {
- var err error
- outputToDir = true
- output, err = ioutil.TempDir("", "varlink_send")
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- }
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if call.WantsMore() {
- call.Continues = true
- }
-
- saveOutput := bytes.NewBuffer([]byte{})
- c := make(chan error)
- go func() {
- err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress, true)
- c <- err
- close(c)
- }()
- var log []string
- done := false
- for {
- line, err := saveOutput.ReadString('\n')
- if err == nil {
- log = append(log, line)
- continue
- } else if err == io.EOF {
- select {
- case err := <-c:
- if err != nil {
- logrus.Errorf("reading of output during save failed for %s", newImage.ID())
- return call.ReplyErrorOccurred(err.Error())
- }
- done = true
- default:
- if !call.WantsMore() {
- break
- }
- br := iopodman.MoreResponse{
- Logs: log,
- }
- call.ReplyImageSave(br)
- log = []string{}
- }
- } else {
- return call.ReplyErrorOccurred(err.Error())
- }
- if done {
- break
- }
- }
- call.Continues = false
-
- sendfile := output
- // Image has been saved to `output`
- if outputToDir {
- // If the output is a directory, we need to tar up the directory to send it back
- // Create a tempfile for the directory tarball
- outputFile, err := ioutil.TempFile("", "varlink_save_dir")
- if err != nil {
- return err
- }
- defer outputFile.Close()
- if err := utils.TarToFilesystem(output, outputFile); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- sendfile = outputFile.Name()
- }
- br := iopodman.MoreResponse{
- Logs: log,
- Id: sendfile,
- }
- return call.ReplyPushImage(br)
-}
-
-// LoadImage ...
-func (i *VarlinkAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, deleteInputFile, quiet bool) error {
- var (
- names string
- writer io.Writer
- err error
- )
- if !quiet {
- writer = os.Stderr
- }
-
- if call.WantsMore() {
- call.Continues = true
- }
- output := bytes.NewBuffer([]byte{})
-
- c := make(chan error)
- go func() {
- names, err = i.Runtime.LoadImage(getContext(), name, inputFile, writer, "")
- c <- err
- close(c)
- }()
-
- var log []string
- done := false
- for {
- line, err := output.ReadString('\n')
- if err == nil {
- log = append(log, line)
- continue
- } else if err == io.EOF {
- select {
- case err := <-c:
- if err != nil {
- logrus.Error(err)
- return call.ReplyErrorOccurred(err.Error())
- }
- done = true
- default:
- if !call.WantsMore() {
- break
- }
- br := iopodman.MoreResponse{
- Logs: log,
- }
- call.ReplyLoadImage(br)
- log = []string{}
- }
- } else {
- return call.ReplyErrorOccurred(err.Error())
- }
- if done {
- break
- }
- }
- call.Continues = false
-
- br := iopodman.MoreResponse{
- Logs: log,
- Id: names,
- }
- if deleteInputFile {
- if err := os.Remove(inputFile); err != nil {
- logrus.Errorf("unable to delete input file %s", inputFile)
- }
- }
- return call.ReplyLoadImage(br)
-}
-
-// Diff ...
-func (i *VarlinkAPI) Diff(call iopodman.VarlinkCall, name string) error {
- var response []iopodman.DiffInfo
- changes, err := i.Runtime.GetDiff("", name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- for _, change := range changes {
- response = append(response, iopodman.DiffInfo{Path: change.Path, ChangeType: change.Kind.String()})
- }
- return call.ReplyDiff(response)
-}
-
-// GetLayersMapWithImageInfo is a development only endpoint to obtain layer information for an image.
-func (i *VarlinkAPI) GetLayersMapWithImageInfo(call iopodman.VarlinkCall) error {
- layerInfo, err := image.GetLayersMapWithImageInfo(i.Runtime.ImageRuntime())
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- b, err := json.Marshal(layerInfo)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyGetLayersMapWithImageInfo(string(b))
-}
-
-// BuildImageHierarchyMap ...
-func (i *VarlinkAPI) BuildImageHierarchyMap(call iopodman.VarlinkCall, name string) error {
- img, err := i.Runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- imageInfo := &image.InfoImage{
- ID: img.ID(),
- Tags: img.Names(),
- }
- layerInfo, err := image.GetLayersMapWithImageInfo(i.Runtime.ImageRuntime())
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if err := image.BuildImageHierarchyMap(imageInfo, layerInfo, img.TopLayer()); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- b, err := json.Marshal(imageInfo)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyBuildImageHierarchyMap(string(b))
-}
-
-// ImageTree returns the image tree string for the provided image name or ID
-func (i *VarlinkAPI) ImageTree(call iopodman.VarlinkCall, nameOrID string, whatRequires bool) error {
- img, err := i.Runtime.ImageRuntime().NewFromLocal(nameOrID)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- tree, err := img.GenerateTree(whatRequires)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyImageTree(tree)
-}
diff --git a/pkg/varlinkapi/intermediate.go b/pkg/varlinkapi/intermediate.go
deleted file mode 100644
index f04665a86..000000000
--- a/pkg/varlinkapi/intermediate.go
+++ /dev/null
@@ -1,289 +0,0 @@
-package varlinkapi
-
-import (
- "github.com/sirupsen/logrus"
-)
-
-/*
-attention
-
-in this file you will see a lot of struct duplication. this was done because people wanted a strongly typed
-varlink mechanism. this resulted in us creating this intermediate layer that allows us to take the input
-from the cli and make an intermediate layer which can be transferred as strongly typed structures over a varlink
-interface.
-
-we intentionally avoided heavy use of reflection here because we were concerned about performance impacts to the
-non-varlink intermediate layer generation.
-*/
-
-// GenericCLIResult describes the overall interface for dealing with
-// the create command cli in both local and remote uses
-type GenericCLIResult interface {
- IsSet() bool
- Name() string
- Value() interface{}
-}
-
-// CRStringSlice describes a string slice cli struct
-type CRStringSlice struct {
- Val []string
- createResult
-}
-
-// CRString describes a string cli struct
-type CRString struct {
- Val string
- createResult
-}
-
-// CRUint64 describes a uint64 cli struct
-type CRUint64 struct {
- Val uint64
- createResult
-}
-
-// CRFloat64 describes a float64 cli struct
-type CRFloat64 struct {
- Val float64
- createResult
-}
-
-//CRBool describes a bool cli struct
-type CRBool struct {
- Val bool
- createResult
-}
-
-// CRInt64 describes an int64 cli struct
-type CRInt64 struct {
- Val int64
- createResult
-}
-
-// CRUint describes a uint cli struct
-type CRUint struct {
- Val uint
- createResult
-}
-
-// CRInt describes an int cli struct
-type CRInt struct {
- Val int
- createResult
-}
-
-// CRStringArray describes a stringarray cli struct
-type CRStringArray struct {
- Val []string
- createResult
-}
-
-type createResult struct {
- Flag string
- Changed bool
-}
-
-// GenericCLIResults in the intermediate object between the cobra cli
-// and createconfig
-type GenericCLIResults struct {
- results map[string]GenericCLIResult
- InputArgs []string
-}
-
-// IsSet returns a bool if the flag was changed
-func (f GenericCLIResults) IsSet(flag string) bool {
- r := f.findResult(flag)
- if r == nil {
- return false
- }
- return r.IsSet()
-}
-
-// Value returns the value of the cli flag
-func (f GenericCLIResults) Value(flag string) interface{} {
- r := f.findResult(flag)
- if r == nil {
- return ""
- }
- return r.Value()
-}
-
-func (f GenericCLIResults) findResult(flag string) GenericCLIResult {
- val, ok := f.results[flag]
- if ok {
- return val
- }
- logrus.Debugf("unable to find flag %s", flag)
- return nil
-}
-
-// Bool is a wrapper to get a bool value from GenericCLIResults
-func (f GenericCLIResults) Bool(flag string) bool {
- r := f.findResult(flag)
- if r == nil {
- return false
- }
- return r.Value().(bool)
-}
-
-// String is a wrapper to get a string value from GenericCLIResults
-func (f GenericCLIResults) String(flag string) string {
- r := f.findResult(flag)
- if r == nil {
- return ""
- }
- return r.Value().(string)
-}
-
-// Uint is a wrapper to get an uint value from GenericCLIResults
-func (f GenericCLIResults) Uint(flag string) uint {
- r := f.findResult(flag)
- if r == nil {
- return 0
- }
- return r.Value().(uint)
-}
-
-// StringSlice is a wrapper to get a stringslice value from GenericCLIResults
-func (f GenericCLIResults) StringSlice(flag string) []string {
- r := f.findResult(flag)
- if r == nil {
- return []string{}
- }
- return r.Value().([]string)
-}
-
-// StringArray is a wrapper to get a stringslice value from GenericCLIResults
-func (f GenericCLIResults) StringArray(flag string) []string {
- r := f.findResult(flag)
- if r == nil {
- return []string{}
- }
- return r.Value().([]string)
-}
-
-// Uint64 is a wrapper to get an uint64 value from GenericCLIResults
-func (f GenericCLIResults) Uint64(flag string) uint64 {
- r := f.findResult(flag)
- if r == nil {
- return 0
- }
- return r.Value().(uint64)
-}
-
-// Int64 is a wrapper to get an int64 value from GenericCLIResults
-func (f GenericCLIResults) Int64(flag string) int64 {
- r := f.findResult(flag)
- if r == nil {
- return 0
- }
- return r.Value().(int64)
-}
-
-// Int is a wrapper to get an int value from GenericCLIResults
-func (f GenericCLIResults) Int(flag string) int {
- r := f.findResult(flag)
- if r == nil {
- return 0
- }
- return r.Value().(int)
-}
-
-// Float64 is a wrapper to get an float64 value from GenericCLIResults
-func (f GenericCLIResults) Float64(flag string) float64 {
- r := f.findResult(flag)
- if r == nil {
- return 0
- }
- return r.Value().(float64)
-}
-
-// Float64 is a wrapper to get an float64 value from GenericCLIResults
-func (f GenericCLIResults) Changed(flag string) bool {
- r := f.findResult(flag)
- if r == nil {
- return false
- }
- return r.IsSet()
-}
-
-// IsSet ...
-func (c CRStringSlice) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRStringSlice) Name() string { return c.Flag }
-
-// Value ...
-func (c CRStringSlice) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRString) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRString) Name() string { return c.Flag }
-
-// Value ...
-func (c CRString) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRUint64) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRUint64) Name() string { return c.Flag }
-
-// Value ...
-func (c CRUint64) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRFloat64) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRFloat64) Name() string { return c.Flag }
-
-// Value ...
-func (c CRFloat64) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRBool) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRBool) Name() string { return c.Flag }
-
-// Value ...
-func (c CRBool) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRInt64) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRInt64) Name() string { return c.Flag }
-
-// Value ...
-func (c CRInt64) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRUint) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRUint) Name() string { return c.Flag }
-
-// Value ...
-func (c CRUint) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRInt) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRInt) Name() string { return c.Flag }
-
-// Value ...
-func (c CRInt) Value() interface{} { return c.Val }
-
-// IsSet ...
-func (c CRStringArray) IsSet() bool { return c.Changed }
-
-// Name ...
-func (c CRStringArray) Name() string { return c.Flag }
-
-// Value ...
-func (c CRStringArray) Value() interface{} { return c.Val }
diff --git a/pkg/varlinkapi/intermediate_varlink.go b/pkg/varlinkapi/intermediate_varlink.go
deleted file mode 100644
index 0d74f1a95..000000000
--- a/pkg/varlinkapi/intermediate_varlink.go
+++ /dev/null
@@ -1,457 +0,0 @@
-// +build varlink remoteclient
-
-package varlinkapi
-
-import (
- "github.com/containers/common/pkg/config"
- "github.com/containers/podman/v2/pkg/rootless"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/pkg/errors"
-)
-
-//FIXME these are duplicated here to resolve a circular
-//import with cmd/podman/common.
-var (
- // DefaultHealthCheckInterval default value
- DefaultHealthCheckInterval = "30s"
- // DefaultHealthCheckRetries default value
- DefaultHealthCheckRetries uint = 3
- // DefaultHealthCheckStartPeriod default value
- DefaultHealthCheckStartPeriod = "0s"
- // DefaultHealthCheckTimeout default value
- DefaultHealthCheckTimeout = "30s"
- // DefaultImageVolume default value
- DefaultImageVolume = "bind"
-)
-
-// StringSliceToPtr converts a genericcliresult value into a *[]string
-func StringSliceToPtr(g GenericCLIResult) *[]string {
- if !g.IsSet() {
- return nil
- }
- newT := g.Value().([]string)
- return &newT
-}
-
-// StringToPtr converts a genericcliresult value into a *string
-func StringToPtr(g GenericCLIResult) *string {
- if !g.IsSet() {
- return nil
- }
- newT := g.Value().(string)
- return &newT
-}
-
-// BoolToPtr converts a genericcliresult value into a *bool
-func BoolToPtr(g GenericCLIResult) *bool {
- if !g.IsSet() {
- return nil
- }
- newT := g.Value().(bool)
- return &newT
-}
-
-// AnyIntToInt64Ptr converts a genericcliresult value into an *int64
-func AnyIntToInt64Ptr(g GenericCLIResult) *int64 {
- if !g.IsSet() {
- return nil
- }
- var newT int64
- switch g.Value().(type) {
- case int:
- newT = int64(g.Value().(int))
- case int64:
- newT = g.Value().(int64)
- case uint64:
- newT = int64(g.Value().(uint64))
- case uint:
- newT = int64(g.Value().(uint))
- default:
- panic(errors.Errorf("invalid int type"))
- }
- return &newT
-}
-
-// Float64ToPtr converts a genericcliresult into a *float64
-func Float64ToPtr(g GenericCLIResult) *float64 {
- if !g.IsSet() {
- return nil
- }
- newT := g.Value().(float64)
- return &newT
-}
-
-// MakeVarlink creates a varlink transportable struct from GenericCLIResults
-func (g GenericCLIResults) MakeVarlink() iopodman.Create {
- v := iopodman.Create{
- Args: g.InputArgs,
- AddHost: StringSliceToPtr(g.Find("add-host")),
- Annotation: StringSliceToPtr(g.Find("annotation")),
- Attach: StringSliceToPtr(g.Find("attach")),
- BlkioWeight: StringToPtr(g.Find("blkio-weight")),
- BlkioWeightDevice: StringSliceToPtr(g.Find("blkio-weight-device")),
- CapAdd: StringSliceToPtr(g.Find("cap-add")),
- CapDrop: StringSliceToPtr(g.Find("cap-drop")),
- CgroupParent: StringToPtr(g.Find("cgroup-parent")),
- CidFile: StringToPtr(g.Find("cidfile")),
- ConmonPidfile: StringToPtr(g.Find("conmon-pidfile")),
- CpuPeriod: AnyIntToInt64Ptr(g.Find("cpu-period")),
- CpuQuota: AnyIntToInt64Ptr(g.Find("cpu-quota")),
- CpuRtPeriod: AnyIntToInt64Ptr(g.Find("cpu-rt-period")),
- CpuRtRuntime: AnyIntToInt64Ptr(g.Find("cpu-rt-runtime")),
- CpuShares: AnyIntToInt64Ptr(g.Find("cpu-shares")),
- Cpus: Float64ToPtr(g.Find("cpus")),
- CpuSetCpus: StringToPtr(g.Find("cpuset-cpus")),
- CpuSetMems: StringToPtr(g.Find("cpuset-mems")),
- Detach: BoolToPtr(g.Find("detach")),
- DetachKeys: StringToPtr(g.Find("detach-keys")),
- Device: StringSliceToPtr(g.Find("device")),
- DeviceReadBps: StringSliceToPtr(g.Find("device-read-bps")),
- DeviceReadIops: StringSliceToPtr(g.Find("device-read-iops")),
- DeviceWriteBps: StringSliceToPtr(g.Find("device-write-bps")),
- DeviceWriteIops: StringSliceToPtr(g.Find("device-write-iops")),
- Dns: StringSliceToPtr(g.Find("dns")),
- DnsOpt: StringSliceToPtr(g.Find("dns-opt")),
- DnsSearch: StringSliceToPtr(g.Find("dns-search")),
- Entrypoint: StringToPtr(g.Find("entrypoint")),
- Env: StringSliceToPtr(g.Find("env")),
- EnvFile: StringSliceToPtr(g.Find("env-file")),
- Expose: StringSliceToPtr(g.Find("expose")),
- Gidmap: StringSliceToPtr(g.Find("gidmap")),
- Groupadd: StringSliceToPtr(g.Find("group-add")),
- HealthcheckCommand: StringToPtr(g.Find("healthcheck-command")),
- HealthcheckInterval: StringToPtr(g.Find("healthcheck-interval")),
- HealthcheckRetries: AnyIntToInt64Ptr(g.Find("healthcheck-retries")),
- HealthcheckStartPeriod: StringToPtr(g.Find("healthcheck-start-period")),
- HealthcheckTimeout: StringToPtr(g.Find("healthcheck-timeout")),
- Hostname: StringToPtr(g.Find("hostname")),
- ImageVolume: StringToPtr(g.Find("image-volume")),
- Init: BoolToPtr(g.Find("init")),
- InitPath: StringToPtr(g.Find("init-path")),
- Interactive: BoolToPtr(g.Find("interactive")),
- Ip: StringToPtr(g.Find("ip")),
- Ipc: StringToPtr(g.Find("ipc")),
- KernelMemory: StringToPtr(g.Find("kernel-memory")),
- Label: StringSliceToPtr(g.Find("label")),
- LabelFile: StringSliceToPtr(g.Find("label-file")),
- LogDriver: StringToPtr(g.Find("log-driver")),
- LogOpt: StringSliceToPtr(g.Find("log-opt")),
- MacAddress: StringToPtr(g.Find("mac-address")),
- Memory: StringToPtr(g.Find("memory")),
- MemoryReservation: StringToPtr(g.Find("memory-reservation")),
- MemorySwap: StringToPtr(g.Find("memory-swap")),
- MemorySwappiness: AnyIntToInt64Ptr(g.Find("memory-swappiness")),
- Name: StringToPtr(g.Find("name")),
- Network: StringToPtr(g.Find("network")),
- OomKillDisable: BoolToPtr(g.Find("oom-kill-disable")),
- OomScoreAdj: AnyIntToInt64Ptr(g.Find("oom-score-adj")),
- OverrideOS: StringToPtr(g.Find("override-os")),
- OverrideArch: StringToPtr(g.Find("override-arch")),
- Pid: StringToPtr(g.Find("pid")),
- PidsLimit: AnyIntToInt64Ptr(g.Find("pids-limit")),
- Pod: StringToPtr(g.Find("pod")),
- Privileged: BoolToPtr(g.Find("privileged")),
- Publish: StringSliceToPtr(g.Find("publish")),
- PublishAll: BoolToPtr(g.Find("publish-all")),
- Pull: StringToPtr(g.Find("pull")),
- Quiet: BoolToPtr(g.Find("quiet")),
- Readonly: BoolToPtr(g.Find("read-only")),
- Readonlytmpfs: BoolToPtr(g.Find("read-only-tmpfs")),
- Restart: StringToPtr(g.Find("restart")),
- Rm: BoolToPtr(g.Find("rm")),
- Rootfs: BoolToPtr(g.Find("rootfs")),
- SecurityOpt: StringSliceToPtr(g.Find("security-opt")),
- ShmSize: StringToPtr(g.Find("shm-size")),
- StopSignal: StringToPtr(g.Find("stop-signal")),
- StopTimeout: AnyIntToInt64Ptr(g.Find("stop-timeout")),
- StorageOpt: StringSliceToPtr(g.Find("storage-opt")),
- Subuidname: StringToPtr(g.Find("subuidname")),
- Subgidname: StringToPtr(g.Find("subgidname")),
- Sysctl: StringSliceToPtr(g.Find("sysctl")),
- Systemd: StringToPtr(g.Find("systemd")),
- Tmpfs: StringSliceToPtr(g.Find("tmpfs")),
- Tty: BoolToPtr(g.Find("tty")),
- Uidmap: StringSliceToPtr(g.Find("uidmap")),
- Ulimit: StringSliceToPtr(g.Find("ulimit")),
- User: StringToPtr(g.Find("user")),
- Userns: StringToPtr(g.Find("userns")),
- Uts: StringToPtr(g.Find("uts")),
- Mount: StringSliceToPtr(g.Find("mount")),
- Volume: StringSliceToPtr(g.Find("volume")),
- VolumesFrom: StringSliceToPtr(g.Find("volumes-from")),
- WorkDir: StringToPtr(g.Find("workdir")),
- }
-
- return v
-}
-
-func stringSliceFromVarlink(v *[]string, flagName string, defaultValue *[]string) CRStringSlice {
- cr := CRStringSlice{}
- if v == nil {
- cr.Val = []string{}
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = *v
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func stringFromVarlink(v *string, flagName string, defaultValue *string) CRString {
- cr := CRString{}
- if v == nil {
- cr.Val = ""
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = *v
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func boolFromVarlink(v *bool, flagName string, defaultValue bool) CRBool {
- cr := CRBool{}
- if v == nil {
- // In case a cli bool default value is true
- cr.Val = defaultValue
- cr.Changed = false
- } else {
- cr.Val = *v
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func uint64FromVarlink(v *int64, flagName string, defaultValue *uint64) CRUint64 {
- cr := CRUint64{}
- if v == nil {
- cr.Val = 0
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = uint64(*v)
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func int64FromVarlink(v *int64, flagName string, defaultValue *int64) CRInt64 {
- cr := CRInt64{}
- if v == nil {
- cr.Val = 0
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = *v
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func float64FromVarlink(v *float64, flagName string, defaultValue *float64) CRFloat64 {
- cr := CRFloat64{}
- if v == nil {
- cr.Val = 0
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = *v
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func uintFromVarlink(v *int64, flagName string, defaultValue *uint) CRUint {
- cr := CRUint{}
- if v == nil {
- cr.Val = 0
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = uint(*v)
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func stringArrayFromVarlink(v *[]string, flagName string, defaultValue *[]string) CRStringArray {
- cr := CRStringArray{}
- if v == nil {
- cr.Val = []string{}
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Changed = false
- } else {
- cr.Val = *v
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-func intFromVarlink(v *int64, flagName string, defaultValue *int) CRInt {
- cr := CRInt{}
- if v == nil {
- if defaultValue != nil {
- cr.Val = *defaultValue
- }
- cr.Val = 0
- cr.Changed = false
- } else {
- cr.Val = int(*v)
- cr.Changed = true
- }
- cr.Flag = flagName
- return cr
-}
-
-// VarlinkCreateToGeneric creates a GenericCLIResults from the varlink create
-// structure.
-func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
- // FIXME this will need to be fixed!!!!! With containers conf
- //containerConfig := cliconfig.GetDefaultConfig()
- // TODO | WARN
- // We do not get a default network over varlink. Unlike the other default values for some cli
- // elements, it seems it gets set to the default anyway.
-
- var memSwapDefault int64 = -1
- netModeDefault := "bridge"
- systemdDefault := "true"
- if rootless.IsRootless() {
- netModeDefault = "slirp4netns"
- }
-
- shmSize := config.DefaultShmSize
-
- m := make(map[string]GenericCLIResult)
- m["add-host"] = stringSliceFromVarlink(opts.AddHost, "add-host", nil)
- m["annotation"] = stringSliceFromVarlink(opts.Annotation, "annotation", nil)
- m["attach"] = stringSliceFromVarlink(opts.Attach, "attach", nil)
- m["blkio-weight"] = stringFromVarlink(opts.BlkioWeight, "blkio-weight", nil)
- m["blkio-weight-device"] = stringSliceFromVarlink(opts.BlkioWeightDevice, "blkio-weight-device", nil)
- m["cap-add"] = stringSliceFromVarlink(opts.CapAdd, "cap-add", nil)
- m["cap-drop"] = stringSliceFromVarlink(opts.CapDrop, "cap-drop", nil)
- m["cgroup-parent"] = stringFromVarlink(opts.CgroupParent, "cgroup-parent", nil)
- m["cidfile"] = stringFromVarlink(opts.CidFile, "cidfile", nil)
- m["conmon-pidfile"] = stringFromVarlink(opts.ConmonPidfile, "conmon-file", nil)
- m["cpu-period"] = uint64FromVarlink(opts.CpuPeriod, "cpu-period", nil)
- m["cpu-quota"] = int64FromVarlink(opts.CpuQuota, "quota", nil)
- m["cpu-rt-period"] = uint64FromVarlink(opts.CpuRtPeriod, "cpu-rt-period", nil)
- m["cpu-rt-runtime"] = int64FromVarlink(opts.CpuRtRuntime, "cpu-rt-quota", nil)
- m["cpu-shares"] = uint64FromVarlink(opts.CpuShares, "cpu-shares", nil)
- m["cpus"] = float64FromVarlink(opts.Cpus, "cpus", nil)
- m["cpuset-cpus"] = stringFromVarlink(opts.CpuSetCpus, "cpuset-cpus", nil)
- m["cpuset-mems"] = stringFromVarlink(opts.CpuSetMems, "cpuset-mems", nil)
- m["detach"] = boolFromVarlink(opts.Detach, "detach", false)
- m["detach-keys"] = stringFromVarlink(opts.DetachKeys, "detach-keys", nil)
- m["device"] = stringSliceFromVarlink(opts.Device, "device", nil)
- m["device-read-bps"] = stringSliceFromVarlink(opts.DeviceReadBps, "device-read-bps", nil)
- m["device-read-iops"] = stringSliceFromVarlink(opts.DeviceReadIops, "device-read-iops", nil)
- m["device-write-bps"] = stringSliceFromVarlink(opts.DeviceWriteBps, "write-device-bps", nil)
- m["device-write-iops"] = stringSliceFromVarlink(opts.DeviceWriteIops, "write-device-iops", nil)
- m["dns"] = stringSliceFromVarlink(opts.Dns, "dns", nil)
- m["dns-opt"] = stringSliceFromVarlink(opts.DnsOpt, "dns-opt", nil)
- m["dns-search"] = stringSliceFromVarlink(opts.DnsSearch, "dns-search", nil)
- m["entrypoint"] = stringFromVarlink(opts.Entrypoint, "entrypoint", nil)
- m["env"] = stringArrayFromVarlink(opts.Env, "env", nil)
- m["env-file"] = stringSliceFromVarlink(opts.EnvFile, "env-file", nil)
- m["expose"] = stringSliceFromVarlink(opts.Expose, "expose", nil)
- m["gidmap"] = stringSliceFromVarlink(opts.Gidmap, "gidmap", nil)
- m["group-add"] = stringSliceFromVarlink(opts.Groupadd, "group-add", nil)
- m["healthcheck-command"] = stringFromVarlink(opts.HealthcheckCommand, "healthcheck-command", nil)
- m["healthcheck-interval"] = stringFromVarlink(opts.HealthcheckInterval, "healthcheck-interval", &DefaultHealthCheckInterval)
- m["healthcheck-retries"] = uintFromVarlink(opts.HealthcheckRetries, "healthcheck-retries", &DefaultHealthCheckRetries)
- m["healthcheck-start-period"] = stringFromVarlink(opts.HealthcheckStartPeriod, "healthcheck-start-period", &DefaultHealthCheckStartPeriod)
- m["healthcheck-timeout"] = stringFromVarlink(opts.HealthcheckTimeout, "healthcheck-timeout", &DefaultHealthCheckTimeout)
- m["hostname"] = stringFromVarlink(opts.Hostname, "hostname", nil)
- m["image-volume"] = stringFromVarlink(opts.ImageVolume, "image-volume", &DefaultImageVolume)
- m["init"] = boolFromVarlink(opts.Init, "init", false)
- m["init-path"] = stringFromVarlink(opts.InitPath, "init-path", nil)
- m["interactive"] = boolFromVarlink(opts.Interactive, "interactive", false)
- m["ip"] = stringFromVarlink(opts.Ip, "ip", nil)
- m["ipc"] = stringFromVarlink(opts.Ipc, "ipc", nil)
- m["kernel-memory"] = stringFromVarlink(opts.KernelMemory, "kernel-memory", nil)
- m["label"] = stringArrayFromVarlink(opts.Label, "label", nil)
- m["label-file"] = stringSliceFromVarlink(opts.LabelFile, "label-file", nil)
- m["log-driver"] = stringFromVarlink(opts.LogDriver, "log-driver", nil)
- m["log-opt"] = stringSliceFromVarlink(opts.LogOpt, "log-opt", nil)
- m["mac-address"] = stringFromVarlink(opts.MacAddress, "mac-address", nil)
- m["memory"] = stringFromVarlink(opts.Memory, "memory", nil)
- m["memory-reservation"] = stringFromVarlink(opts.MemoryReservation, "memory-reservation", nil)
- m["memory-swap"] = stringFromVarlink(opts.MemorySwap, "memory-swap", nil)
- m["memory-swappiness"] = int64FromVarlink(opts.MemorySwappiness, "memory-swappiness", &memSwapDefault)
- m["name"] = stringFromVarlink(opts.Name, "name", nil)
- m["network"] = stringFromVarlink(opts.Network, "network", &netModeDefault)
- m["no-hosts"] = boolFromVarlink(opts.NoHosts, "no-hosts", false)
- m["oom-kill-disable"] = boolFromVarlink(opts.OomKillDisable, "oon-kill-disable", false)
- m["oom-score-adj"] = intFromVarlink(opts.OomScoreAdj, "oom-score-adj", nil)
- m["override-os"] = stringFromVarlink(opts.OverrideOS, "override-os", nil)
- m["override-arch"] = stringFromVarlink(opts.OverrideArch, "override-arch", nil)
- m["pid"] = stringFromVarlink(opts.Pid, "pid", nil)
- m["pids-limit"] = int64FromVarlink(opts.PidsLimit, "pids-limit", nil)
- m["pod"] = stringFromVarlink(opts.Pod, "pod", nil)
- m["privileged"] = boolFromVarlink(opts.Privileged, "privileged", false)
- m["publish"] = stringSliceFromVarlink(opts.Publish, "publish", nil)
- m["publish-all"] = boolFromVarlink(opts.PublishAll, "publish-all", false)
- m["pull"] = stringFromVarlink(opts.Pull, "missing", nil)
- m["quiet"] = boolFromVarlink(opts.Quiet, "quiet", false)
- m["read-only"] = boolFromVarlink(opts.Readonly, "read-only", false)
- m["read-only-tmpfs"] = boolFromVarlink(opts.Readonlytmpfs, "read-only-tmpfs", true)
- m["restart"] = stringFromVarlink(opts.Restart, "restart", nil)
- m["rm"] = boolFromVarlink(opts.Rm, "rm", false)
- m["rootfs"] = boolFromVarlink(opts.Rootfs, "rootfs", false)
- m["security-opt"] = stringArrayFromVarlink(opts.SecurityOpt, "security-opt", nil)
- m["shm-size"] = stringFromVarlink(opts.ShmSize, "shm-size", &shmSize)
- m["stop-signal"] = stringFromVarlink(opts.StopSignal, "stop-signal", nil)
- m["stop-timeout"] = uintFromVarlink(opts.StopTimeout, "stop-timeout", nil)
- m["storage-opt"] = stringSliceFromVarlink(opts.StorageOpt, "storage-opt", nil)
- m["subgidname"] = stringFromVarlink(opts.Subgidname, "subgidname", nil)
- m["subuidname"] = stringFromVarlink(opts.Subuidname, "subuidname", nil)
- m["sysctl"] = stringSliceFromVarlink(opts.Sysctl, "sysctl", nil)
- m["systemd"] = stringFromVarlink(opts.Systemd, "systemd", &systemdDefault)
- m["tmpfs"] = stringSliceFromVarlink(opts.Tmpfs, "tmpfs", nil)
- m["tty"] = boolFromVarlink(opts.Tty, "tty", false)
- m["uidmap"] = stringSliceFromVarlink(opts.Uidmap, "uidmap", nil)
- m["ulimit"] = stringSliceFromVarlink(opts.Ulimit, "ulimit", nil)
- m["user"] = stringFromVarlink(opts.User, "user", nil)
- m["userns"] = stringFromVarlink(opts.Userns, "userns", nil)
- m["uts"] = stringFromVarlink(opts.Uts, "uts", nil)
- m["mount"] = stringArrayFromVarlink(opts.Mount, "mount", nil)
- m["volume"] = stringArrayFromVarlink(opts.Volume, "volume", nil)
- m["volumes-from"] = stringSliceFromVarlink(opts.VolumesFrom, "volumes-from", nil)
- m["workdir"] = stringFromVarlink(opts.WorkDir, "workdir", nil)
-
- gcli := GenericCLIResults{m, opts.Args}
- return gcli
-}
-
-// Find returns a flag from a GenericCLIResults by name
-func (g GenericCLIResults) Find(name string) GenericCLIResult {
- result, ok := g.results[name]
- if ok {
- return result
- }
- panic(errors.Errorf("unable to find generic flag for varlink %s", name))
-}
diff --git a/pkg/varlinkapi/mount.go b/pkg/varlinkapi/mount.go
deleted file mode 100644
index 6fd4de709..000000000
--- a/pkg/varlinkapi/mount.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import iopodman "github.com/containers/podman/v2/pkg/varlink"
-
-// ListContainerMounts ...
-func (i *VarlinkAPI) ListContainerMounts(call iopodman.VarlinkCall) error {
- mounts := make(map[string]string)
- allContainers, err := i.Runtime.GetAllContainers()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- for _, container := range allContainers {
- mounted, mountPoint, err := container.Mounted()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if mounted {
- mounts[container.ID()] = mountPoint
- }
- }
- return call.ReplyListContainerMounts(mounts)
-}
-
-// MountContainer ...
-func (i *VarlinkAPI) MountContainer(call iopodman.VarlinkCall, name string) error {
- container, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- path, err := container.Mount()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyMountContainer(path)
-}
-
-// UnmountContainer ...
-func (i *VarlinkAPI) UnmountContainer(call iopodman.VarlinkCall, name string, force bool) error {
- container, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if err := container.Unmount(force); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyUnmountContainer()
-}
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
deleted file mode 100644
index 6d03afb7a..000000000
--- a/pkg/varlinkapi/pods.go
+++ /dev/null
@@ -1,389 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "strconv"
- "syscall"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/go-connections/nat"
- "github.com/pkg/errors"
-)
-
-// CreatePod ...
-func (i *VarlinkAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCreate) error {
- var options []libpod.PodCreateOption
- if create.Infra {
- options = append(options, libpod.WithInfraContainer())
- nsOptions, err := GetNamespaceOptions(create.Share)
- if err != nil {
- return err
- }
- options = append(options, nsOptions...)
- }
- if create.CgroupParent != "" {
- options = append(options, libpod.WithPodCgroupParent(create.CgroupParent))
- }
- if len(create.Labels) > 0 {
- options = append(options, libpod.WithPodLabels(create.Labels))
- }
- if create.Name != "" {
- options = append(options, libpod.WithPodName(create.Name))
- }
- if len(create.Share) > 0 && !create.Infra {
- return call.ReplyErrorOccurred("You cannot share kernel namespaces on the pod level without an infra container")
- }
- if len(create.Share) == 0 && create.Infra {
- return call.ReplyErrorOccurred("You must share kernel namespaces to run an infra container")
- }
-
- if len(create.Publish) > 0 {
- if !create.Infra {
- return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host")
- }
- portBindings, err := CreatePortBindings(create.Publish)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- options = append(options, libpod.WithInfraContainerPorts(portBindings))
-
- }
- options = append(options, libpod.WithPodCgroups())
-
- pod, err := i.Runtime.NewPod(getContext(), options...)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyCreatePod(pod.ID())
-}
-
-// ListPods ...
-func (i *VarlinkAPI) ListPods(call iopodman.VarlinkCall) error {
- var (
- listPods []iopodman.ListPodData
- )
-
- pods, err := i.Runtime.GetAllPods()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- opts := PsOptions{}
- for _, pod := range pods {
- listPod, err := makeListPod(pod, opts)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- listPods = append(listPods, listPod)
- }
- return call.ReplyListPods(listPods)
-}
-
-// GetPod ...
-func (i *VarlinkAPI) GetPod(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- opts := PsOptions{}
-
- listPod, err := makeListPod(pod, opts)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- return call.ReplyGetPod(listPod)
-}
-
-// GetPodsByStatus returns a slice of pods filtered by a libpod status
-func (i *VarlinkAPI) GetPodsByStatus(call iopodman.VarlinkCall, statuses []string) error {
- filterFuncs := func(p *libpod.Pod) bool {
- state, _ := p.GetPodStatus()
- for _, status := range statuses {
- if state == status {
- return true
- }
- }
- return false
- }
- filteredPods, err := i.Runtime.Pods(filterFuncs)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- podIDs := make([]string, 0, len(filteredPods))
- for _, p := range filteredPods {
- podIDs = append(podIDs, p.ID())
- }
- return call.ReplyGetPodsByStatus(podIDs)
-}
-
-// InspectPod ...
-func (i *VarlinkAPI) InspectPod(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- inspectData, err := pod.Inspect()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- b, err := json.Marshal(&inspectData)
- if err != nil {
- return call.ReplyErrorOccurred("unable to serialize")
- }
- return call.ReplyInspectPod(string(b))
-}
-
-// StartPod ...
-func (i *VarlinkAPI) StartPod(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- ctnrs, err := pod.AllContainers()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if 0 == len(ctnrs) {
- return call.ReplyNoContainersInPod(name)
- }
- ctrErrs, err := pod.Start(getContext())
- callErr := handlePodCall(call, pod, ctrErrs, err)
- if callErr != nil {
- return err
- }
- return call.ReplyStartPod(pod.ID())
-}
-
-// StopPod ...
-func (i *VarlinkAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int64) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- ctrErrs, err := pod.StopWithTimeout(getContext(), true, int(timeout))
- callErr := handlePodCall(call, pod, ctrErrs, err)
- if callErr != nil {
- return err
- }
- return call.ReplyStopPod(pod.ID())
-}
-
-// RestartPod ...
-func (i *VarlinkAPI) RestartPod(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- ctnrs, err := pod.AllContainers()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if 0 == len(ctnrs) {
- return call.ReplyNoContainersInPod(name)
- }
- ctrErrs, err := pod.Restart(getContext())
- callErr := handlePodCall(call, pod, ctrErrs, err)
- if callErr != nil {
- return err
- }
- return call.ReplyRestartPod(pod.ID())
-}
-
-// KillPod kills the running containers in a pod. If you want to use the default SIGTERM signal,
-// just send a -1 for the signal arg.
-func (i *VarlinkAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64) error {
- killSignal := uint(syscall.SIGTERM)
- if signal != -1 {
- killSignal = uint(signal)
- }
-
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- ctrErrs, err := pod.Kill(context.TODO(), killSignal)
- callErr := handlePodCall(call, pod, ctrErrs, err)
- if callErr != nil {
- return err
- }
- return call.ReplyKillPod(pod.ID())
-}
-
-// PausePod ...
-func (i *VarlinkAPI) PausePod(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- ctrErrs, err := pod.Pause(context.TODO())
- callErr := handlePodCall(call, pod, ctrErrs, err)
- if callErr != nil {
- return err
- }
- return call.ReplyPausePod(pod.ID())
-}
-
-// UnpausePod ...
-func (i *VarlinkAPI) UnpausePod(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- ctrErrs, err := pod.Unpause(context.TODO())
- callErr := handlePodCall(call, pod, ctrErrs, err)
- if callErr != nil {
- return err
- }
- return call.ReplyUnpausePod(pod.ID())
-}
-
-// RemovePod ...
-func (i *VarlinkAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool) error {
- ctx := getContext()
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- if err = i.Runtime.RemovePod(ctx, pod, true, force); err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- return call.ReplyRemovePod(pod.ID())
-}
-
-// GetPodStats ...
-func (i *VarlinkAPI) GetPodStats(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
- prevStats := make(map[string]*define.ContainerStats)
- podStats, err := pod.GetPodStats(prevStats)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if len(podStats) == 0 {
- return call.ReplyNoContainerRunning()
- }
- containersStats := make([]iopodman.ContainerStats, 0)
- for ctrID, containerStats := range podStats {
- cs := iopodman.ContainerStats{
- Id: ctrID,
- Name: containerStats.Name,
- Cpu: containerStats.CPU,
- Cpu_nano: int64(containerStats.CPUNano),
- System_nano: int64(containerStats.SystemNano),
- Mem_usage: int64(containerStats.MemUsage),
- Mem_limit: int64(containerStats.MemLimit),
- Mem_perc: containerStats.MemPerc,
- Net_input: int64(containerStats.NetInput),
- Net_output: int64(containerStats.NetOutput),
- Block_input: int64(containerStats.BlockInput),
- Block_output: int64(containerStats.BlockOutput),
- Pids: int64(containerStats.PIDs),
- }
- containersStats = append(containersStats, cs)
- }
- return call.ReplyGetPodStats(pod.ID(), containersStats)
-}
-
-// getPodsByContext returns a slice of pod ids based on all, latest, or a list
-func (i *VarlinkAPI) GetPodsByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error {
- var podids []string
-
- pods, err := getPodsByContext(all, latest, input, i.Runtime)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- for _, p := range pods {
- podids = append(podids, p.ID())
- }
- return call.ReplyGetPodsByContext(podids)
-}
-
-// PodStateData returns a container's state data in string format
-func (i *VarlinkAPI) PodStateData(call iopodman.VarlinkCall, name string) error {
- pod, err := i.Runtime.LookupPod(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- data, err := pod.Inspect()
- if err != nil {
- return call.ReplyErrorOccurred("unable to obtain pod state")
- }
- b, err := json.Marshal(data)
- if err != nil {
- return call.ReplyErrorOccurred("unable to serialize pod inspect data")
- }
- return call.ReplyPodStateData(string(b))
-}
-
-// TopPod provides the top stats for a given or latest pod
-func (i *VarlinkAPI) TopPod(call iopodman.VarlinkCall, name string, latest bool, descriptors []string) error {
- var (
- pod *libpod.Pod
- err error
- )
- if latest {
- name = "latest"
- pod, err = i.Runtime.GetLatestPod()
- } else {
- pod, err = i.Runtime.LookupPod(name)
- }
- if err != nil {
- return call.ReplyPodNotFound(name, err.Error())
- }
-
- podStatus, err := pod.GetPodStatus()
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to get status for pod %s", pod.ID()))
- }
- if podStatus != "Running" {
- return call.ReplyErrorOccurred("pod top can only be used on pods with at least one running container")
- }
- reply, err := pod.GetPodPidInformation(descriptors)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyTopPod(reply)
-}
-
-// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
-func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) {
- var portBindings []ocicni.PortMapping
- // The conversion from []string to natBindings is temporary while mheon reworks the port
- // deduplication code. Eventually that step will not be required.
- _, natBindings, err := nat.ParsePortSpecs(ports)
- if err != nil {
- return nil, err
- }
- for containerPb, hostPb := range natBindings {
- var pm ocicni.PortMapping
- pm.ContainerPort = int32(containerPb.Int())
- for _, i := range hostPb {
- var hostPort int
- var err error
- pm.HostIP = i.HostIP
- if i.HostPort == "" {
- hostPort = containerPb.Int()
- } else {
- hostPort, err = strconv.Atoi(i.HostPort)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to convert host port to integer")
- }
- }
-
- pm.HostPort = int32(hostPort)
- pm.Protocol = containerPb.Proto()
- portBindings = append(portBindings, pm)
- }
- }
- return portBindings, nil
-}
diff --git a/pkg/varlinkapi/remote_client.go b/pkg/varlinkapi/remote_client.go
deleted file mode 100644
index 88c11c126..000000000
--- a/pkg/varlinkapi/remote_client.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// +build varlink remoteclient
-
-package varlinkapi
-
-import (
- "github.com/containers/podman/v2/libpod/define"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
-)
-
-// ContainerStatsToLibpodContainerStats converts the varlink containerstats to a libpod
-// container stats
-func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) define.ContainerStats {
- cstats := define.ContainerStats{
- ContainerID: stats.Id,
- Name: stats.Name,
- CPU: stats.Cpu,
- CPUNano: uint64(stats.Cpu_nano),
- SystemNano: uint64(stats.System_nano),
- MemUsage: uint64(stats.Mem_usage),
- MemLimit: uint64(stats.Mem_limit),
- MemPerc: stats.Mem_perc,
- NetInput: uint64(stats.Net_input),
- NetOutput: uint64(stats.Net_output),
- BlockInput: uint64(stats.Block_input),
- BlockOutput: uint64(stats.Block_output),
- PIDs: uint64(stats.Pids),
- }
- return cstats
-}
diff --git a/pkg/varlinkapi/shortcuts.go b/pkg/varlinkapi/shortcuts.go
deleted file mode 100644
index bfb05c0e3..000000000
--- a/pkg/varlinkapi/shortcuts.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package varlinkapi
-
-import (
- "github.com/containers/podman/v2/libpod"
- "github.com/sirupsen/logrus"
-)
-
-// getPodsByContext returns a slice of pods. Note that all, latest and pods are
-// mutually exclusive arguments.
-func getPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) ([]*libpod.Pod, error) {
- var outpods []*libpod.Pod
- if all {
- return runtime.GetAllPods()
- }
- if latest {
- p, err := runtime.GetLatestPod()
- if err != nil {
- return nil, err
- }
- outpods = append(outpods, p)
- return outpods, nil
- }
- var err error
- for _, p := range pods {
- pod, e := runtime.LookupPod(p)
- if e != nil {
- // Log all errors here, so callers don't need to.
- logrus.Debugf("Error looking up pod %q: %v", p, e)
- if err == nil {
- err = e
- }
- } else {
- outpods = append(outpods, pod)
- }
- }
- return outpods, err
-}
-
-// getContainersByContext gets pods whether all, latest, or a slice of names/ids
-// is specified.
-func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
- var ctr *libpod.Container
- ctrs = []*libpod.Container{}
-
- switch {
- case all:
- ctrs, err = runtime.GetAllContainers()
- case latest:
- ctr, err = runtime.GetLatestContainer()
- ctrs = append(ctrs, ctr)
- default:
- for _, n := range names {
- ctr, e := runtime.LookupContainer(n)
- if e != nil {
- // Log all errors here, so callers don't need to.
- logrus.Debugf("Error looking up container %q: %v", n, e)
- if err == nil {
- err = e
- }
- } else {
- ctrs = append(ctrs, ctr)
- }
- }
- }
- return
-}
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
deleted file mode 100644
index e5c766a6d..000000000
--- a/pkg/varlinkapi/system.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "context"
- "fmt"
- "os"
- goruntime "runtime"
- "strconv"
- "time"
-
- "github.com/containers/image/v5/pkg/sysregistriesv2"
- "github.com/containers/podman/v2/libpod/define"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/sirupsen/logrus"
-)
-
-// GetVersion ...
-func (i *VarlinkAPI) GetVersion(call iopodman.VarlinkCall) error {
- versionInfo, err := define.GetVersion()
- if err != nil {
- return err
- }
-
- int64APIVersion, err := strconv.ParseInt(versionInfo.APIVersion, 10, 64)
- if err != nil {
- return err
- }
-
- return call.ReplyGetVersion(
- versionInfo.Version,
- versionInfo.GoVersion,
- versionInfo.GitCommit,
- time.Unix(versionInfo.Built, 0).Format(time.RFC3339),
- versionInfo.OsArch,
- int64APIVersion,
- )
-}
-
-// GetInfo returns details about the podman host and its stores
-func (i *VarlinkAPI) GetInfo(call iopodman.VarlinkCall) error {
- versionInfo, err := define.GetVersion()
- if err != nil {
- return err
- }
- podmanInfo := iopodman.PodmanInfo{}
- info, err := i.Runtime.Info()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- distribution := iopodman.InfoDistribution{
- Distribution: info.Host.Distribution.Distribution,
- Version: info.Host.Distribution.Version,
- }
- infoHost := iopodman.InfoHost{
- Buildah_version: info.Host.BuildahVersion,
- Distribution: distribution,
- Mem_free: info.Host.MemFree,
- Mem_total: info.Host.MemTotal,
- Swap_free: info.Host.SwapFree,
- Swap_total: info.Host.SwapTotal,
- Arch: info.Host.Arch,
- Cpus: int64(info.Host.CPUs),
- Hostname: info.Host.Hostname,
- Kernel: info.Host.Kernel,
- Os: info.Host.OS,
- Uptime: info.Host.Uptime,
- Eventlogger: info.Host.EventLogger,
- }
- podmanInfo.Host = infoHost
- pmaninfo := iopodman.InfoPodmanBinary{
- Compiler: goruntime.Compiler,
- Go_version: goruntime.Version(),
- Podman_version: versionInfo.Version,
- Git_commit: versionInfo.GitCommit,
- }
-
- graphStatus := iopodman.InfoGraphStatus{
- Backing_filesystem: info.Store.GraphStatus["Backing Filesystem"],
- Native_overlay_diff: info.Store.GraphStatus["Native Overlay Diff"],
- Supports_d_type: info.Store.GraphStatus["Supports d_type"],
- }
- infoStore := iopodman.InfoStore{
- Graph_driver_name: info.Store.GraphDriverName,
- Containers: int64(info.Store.ContainerStore.Number),
- Images: int64(info.Store.ImageStore.Number),
- Run_root: info.Store.RunRoot,
- Graph_root: info.Store.GraphRoot,
- Graph_driver_options: fmt.Sprintf("%v", info.Store.GraphOptions),
- Graph_status: graphStatus,
- }
-
- // Registry information if any is stored as the second list item
- for key, val := range info.Registries {
- if key == "search" {
- podmanInfo.Registries.Search = val.([]string)
- continue
- }
- regData := val.(sysregistriesv2.Registry)
- if regData.Insecure {
- podmanInfo.Registries.Insecure = append(podmanInfo.Registries.Insecure, key)
- }
- if regData.Blocked {
- podmanInfo.Registries.Blocked = append(podmanInfo.Registries.Blocked, key)
- }
- }
- podmanInfo.Store = infoStore
- podmanInfo.Podman = pmaninfo
- return call.ReplyGetInfo(podmanInfo)
-}
-
-// GetVersion ...
-func (i *VarlinkAPI) Reset(call iopodman.VarlinkCall) error {
- if err := i.Runtime.Reset(context.TODO()); err != nil {
- logrus.Errorf("Reset Failed: %v", err)
- if err := call.ReplyErrorOccurred(err.Error()); err != nil {
- logrus.Errorf("Failed to send ReplyErrorOccurred: %v", err)
- }
- os.Exit(define.ExecErrorCodeGeneric)
- }
- if err := call.ReplyReset(); err != nil {
- logrus.Errorf("Failed to send ReplyReset: %v", err)
- os.Exit(define.ExecErrorCodeGeneric)
- }
- os.Exit(0)
- return nil
-}
diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go
deleted file mode 100644
index a4550a417..000000000
--- a/pkg/varlinkapi/transfers.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "bufio"
- "io"
- "io/ioutil"
- "os"
-
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/sirupsen/logrus"
-)
-
-// SendFile allows a client to send a file to the varlink server
-func (i *VarlinkAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int64) error {
- if !call.WantsUpgrade() {
- return call.ReplyErrorOccurred("client must use upgraded connection to send files")
- }
-
- outputFile, err := ioutil.TempFile("", "varlink_send")
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- defer outputFile.Close()
-
- if err = call.ReplySendFile(outputFile.Name()); err != nil {
- // If an error occurs while sending the reply, return the error
- return err
- }
-
- writer := bufio.NewWriter(outputFile)
- defer writer.Flush()
-
- reader := call.Call.Reader
- if _, err := io.CopyN(writer, reader, length); err != nil {
- return err
- }
-
- logrus.Debugf("successfully received %s", outputFile.Name())
- // Send an ACK to the client
- call.Call.Writer.WriteString(outputFile.Name() + ":")
- call.Call.Writer.Flush()
- return nil
-
-}
-
-// ReceiveFile allows the varlink server to send a file to a client
-func (i *VarlinkAPI) ReceiveFile(call iopodman.VarlinkCall, filepath string, delete bool) error {
- if !call.WantsUpgrade() {
- return call.ReplyErrorOccurred("client must use upgraded connection to send files")
- }
- fs, err := os.Open(filepath)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- fileInfo, err := fs.Stat()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
-
- // Send the file length down to client
- // Varlink connection upgraded
- if err = call.ReplyReceiveFile(fileInfo.Size()); err != nil {
- // If an error occurs while sending the reply, return the error
- return err
- }
-
- reader := bufio.NewReader(fs)
- _, err = reader.WriteTo(call.Writer)
- if err != nil {
- return err
- }
- if delete {
- if err := os.Remove(filepath); err != nil {
- return err
- }
- }
- return call.Writer.Flush()
-}
diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go
deleted file mode 100644
index 7f96965f0..000000000
--- a/pkg/varlinkapi/util.go
+++ /dev/null
@@ -1,237 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "context"
- "strconv"
- "strings"
- "time"
-
- "github.com/containers/buildah"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/channel"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
- "github.com/containers/storage/pkg/archive"
-)
-
-// getContext returns a non-nil, empty context
-func getContext() context.Context {
- return context.TODO()
-}
-
-func makeListContainer(containerID string, batchInfo BatchContainerStruct) iopodman.Container {
- var (
- mounts []iopodman.ContainerMount
- ports []iopodman.ContainerPortMappings
- )
- ns := GetNamespaces(batchInfo.Pid)
-
- for _, mount := range batchInfo.ConConfig.Spec.Mounts {
- m := iopodman.ContainerMount{
- Destination: mount.Destination,
- Type: mount.Type,
- Source: mount.Source,
- Options: mount.Options,
- }
- mounts = append(mounts, m)
- }
-
- for _, pm := range batchInfo.ConConfig.PortMappings {
- p := iopodman.ContainerPortMappings{
- Host_port: strconv.Itoa(int(pm.HostPort)),
- Host_ip: pm.HostIP,
- Protocol: pm.Protocol,
- Container_port: strconv.Itoa(int(pm.ContainerPort)),
- }
- ports = append(ports, p)
-
- }
-
- // If we find this needs to be done for other container endpoints, we should
- // convert this to a separate function or a generic map from struct function.
- namespace := iopodman.ContainerNameSpace{
- User: ns.User,
- Uts: ns.UTS,
- Pidns: ns.PIDNS,
- Pid: ns.PID,
- Cgroup: ns.Cgroup,
- Net: ns.NET,
- Mnt: ns.MNT,
- Ipc: ns.IPC,
- }
-
- lc := iopodman.Container{
- Id: containerID,
- Image: batchInfo.ConConfig.RootfsImageName,
- Imageid: batchInfo.ConConfig.RootfsImageID,
- Command: batchInfo.ConConfig.Spec.Process.Args,
- Createdat: batchInfo.ConConfig.CreatedTime.Format(time.RFC3339),
- Runningfor: time.Since(batchInfo.ConConfig.CreatedTime).String(),
- Status: batchInfo.ConState.String(),
- Ports: ports,
- Names: batchInfo.ConConfig.Name,
- Labels: batchInfo.ConConfig.Labels,
- Mounts: mounts,
- Containerrunning: batchInfo.ConState == define.ContainerStateRunning,
- Namespaces: namespace,
- }
- if batchInfo.Size != nil {
- lc.Rootfssize = batchInfo.Size.RootFsSize
- lc.Rwsize = batchInfo.Size.RwSize
- }
- return lc
-}
-
-func makeListPodContainers(containerID string, batchInfo BatchContainerStruct) iopodman.ListPodContainerInfo {
- lc := iopodman.ListPodContainerInfo{
- Id: containerID,
- Status: batchInfo.ConState.String(),
- Name: batchInfo.ConConfig.Name,
- }
- return lc
-}
-
-func makeListPod(pod *libpod.Pod, batchInfo PsOptions) (iopodman.ListPodData, error) {
- var listPodsContainers []iopodman.ListPodContainerInfo
- var errPodData = iopodman.ListPodData{}
- status, err := pod.GetPodStatus()
- if err != nil {
- return errPodData, err
- }
- containers, err := pod.AllContainers()
- if err != nil {
- return errPodData, err
- }
- for _, ctr := range containers {
- batchInfo, err := BatchContainerOp(ctr, batchInfo)
- if err != nil {
- return errPodData, err
- }
-
- listPodsContainers = append(listPodsContainers, makeListPodContainers(ctr.ID(), batchInfo))
- }
- listPod := iopodman.ListPodData{
- Createdat: pod.CreatedTime().Format(time.RFC3339),
- Id: pod.ID(),
- Name: pod.Name(),
- Status: status,
- Cgroup: pod.CgroupParent(),
- Numberofcontainers: strconv.Itoa(len(listPodsContainers)),
- Containersinfo: listPodsContainers,
- }
- return listPod, nil
-}
-
-func handlePodCall(call iopodman.VarlinkCall, pod *libpod.Pod, ctrErrs map[string]error, err error) error {
- if err != nil && ctrErrs == nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- if ctrErrs != nil {
- containerErrs := make([]iopodman.PodContainerErrorData, len(ctrErrs))
- for ctr, reason := range ctrErrs {
- ctrErr := iopodman.PodContainerErrorData{Containerid: ctr, Reason: reason.Error()}
- containerErrs = append(containerErrs, ctrErr)
- }
- return call.ReplyPodContainerError(pod.ID(), containerErrs)
- }
-
- return nil
-}
-
-func stringCompressionToArchiveType(s string) archive.Compression {
- switch strings.ToUpper(s) {
- case "BZIP2":
- return archive.Bzip2
- case "GZIP":
- return archive.Gzip
- case "XZ":
- return archive.Xz
- }
- return archive.Uncompressed
-}
-
-func stringPullPolicyToType(s string) buildah.PullPolicy {
- switch strings.ToUpper(s) {
- case "PULLIFMISSING":
- return buildah.PullIfMissing
- case "PULLALWAYS":
- return buildah.PullAlways
- case "PULLNEVER":
- return buildah.PullNever
- }
- return buildah.PullIfMissing
-}
-
-func derefBool(inBool *bool) bool {
- if inBool == nil {
- return false
- }
- return *inBool
-}
-
-func derefString(in *string) string {
- if in == nil {
- return ""
- }
- return *in
-}
-
-func makePsOpts(inOpts iopodman.PsOpts) PsOptions {
- last := 0
- if inOpts.Last != nil {
- lastT := *inOpts.Last
- last = int(lastT)
- }
- return PsOptions{
- All: inOpts.All,
- Last: last,
- Latest: derefBool(inOpts.Latest),
- NoTrunc: derefBool(inOpts.NoTrunc),
- Pod: derefBool(inOpts.Pod),
- Size: derefBool(inOpts.Size),
- Sort: derefString(inOpts.Sort),
- Namespace: true,
- Sync: derefBool(inOpts.Sync),
- }
-}
-
-// forwardOutput is a helper method for varlink endpoints that employ both more and without
-// more. it is capable of sending updates as the output writer gets them or append them
-// all to a log. the chan error is the error from the libpod call so we can honor
-// and error event in that case.
-func forwardOutput(log []string, c chan error, wantsMore bool, output channel.WriteCloser, reply func(br iopodman.MoreResponse) error) ([]string, error) {
- done := false
- for {
- select {
- // We need to check if the libpod func being called has returned an
- // error yet
- case err := <-c:
- if err != nil {
- return nil, err
- }
- done = true
- // if no error is found, we pull what we can from the log writer and
- // append it to log string slice
- case line := <-output.Chan():
- log = append(log, string(line))
- // If the end point is being used in more mode, send what we have
- if wantsMore {
- br := iopodman.MoreResponse{
- Logs: log,
- }
- if err := reply(br); err != nil {
- return nil, err
- }
- // "reset" the log to empty because we are sending what we
- // get as we get it
- log = []string{}
- }
- }
- if done {
- break
- }
- }
- return log, nil
-}
diff --git a/pkg/varlinkapi/virtwriter/virtwriter.go b/pkg/varlinkapi/virtwriter/virtwriter.go
deleted file mode 100644
index d96e82a3f..000000000
--- a/pkg/varlinkapi/virtwriter/virtwriter.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package virtwriter
-
-import (
- "bufio"
- "encoding/binary"
- "encoding/json"
- "io"
- "time"
-
- "github.com/pkg/errors"
- "k8s.io/client-go/tools/remotecommand"
-)
-
-// SocketDest is the "key" to where IO should go on the varlink
-// multiplexed socket
-type SocketDest int
-
-const (
- // ToStdout indicates traffic should go stdout
- ToStdout SocketDest = iota
- // ToStdin indicates traffic came from stdin
- ToStdin SocketDest = iota
- // ToStderr indicates traffuc should go to stderr
- ToStderr SocketDest = iota
- // TerminalResize indicates a terminal resize event has occurred
- // and data should be passed to resizer
- TerminalResize SocketDest = iota
- // Quit and detach
- Quit SocketDest = iota
- // HangUpFromClient hangs up from the client
- HangUpFromClient SocketDest = iota
-)
-
-// ErrClientHangup signifies that the client wants to drop its connection from
-// the server.
-var ErrClientHangup = errors.New("client hangup")
-
-// IntToSocketDest returns a socketdest based on integer input
-func IntToSocketDest(i int) SocketDest {
- switch i {
- case ToStdout.Int():
- return ToStdout
- case ToStderr.Int():
- return ToStderr
- case ToStdin.Int():
- return ToStdin
- case TerminalResize.Int():
- return TerminalResize
- case Quit.Int():
- return Quit
- case HangUpFromClient.Int():
- return HangUpFromClient
- default:
- return ToStderr
- }
-}
-
-// Int returns the integer representation of the socket dest
-func (sd SocketDest) Int() int {
- return int(sd)
-}
-
-// VirtWriteCloser are writers for attach which include the dest
-// of the data
-type VirtWriteCloser struct {
- writer *bufio.Writer
- dest SocketDest
-}
-
-// NewVirtWriteCloser is a constructor
-func NewVirtWriteCloser(w *bufio.Writer, dest SocketDest) VirtWriteCloser {
- return VirtWriteCloser{w, dest}
-}
-
-// Close is a required method for a writecloser
-func (v VirtWriteCloser) Close() error {
- return v.writer.Flush()
-}
-
-// Write prepends a header to the input message. The header is
-// 8bytes. Position one contains the destination. Positions
-// 5,6,7,8 are a big-endian encoded uint32 for len of the message.
-func (v VirtWriteCloser) Write(input []byte) (int, error) {
- header := []byte{byte(v.dest), 0, 0, 0}
- // Go makes us define the byte for big endian
- mlen := make([]byte, 4)
- binary.BigEndian.PutUint32(mlen, uint32(len(input)))
- // append the message len to the header
- msg := append(header, mlen...)
- // append the message to the header
- msg = append(msg, input...)
- _, err := v.writer.Write(msg)
- if err != nil {
- return 0, err
- }
- err = v.writer.Flush()
- return len(input), err
-}
-
-// Reader decodes the content that comes over the wire and directs it to the proper destination.
-func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remotecommand.TerminalSize, execEcChan chan int) error {
- var messageSize int64
- headerBytes := make([]byte, 8)
-
- if r == nil {
- return errors.Errorf("Reader must not be nil")
- }
- for {
- n, err := io.ReadFull(r, headerBytes)
- if err != nil {
- return errors.Wrapf(err, "Virtual Read failed, %d", n)
- }
- if n < 8 {
- return errors.New("short read and no full header read")
- }
-
- messageSize = int64(binary.BigEndian.Uint32(headerBytes[4:8]))
- switch IntToSocketDest(int(headerBytes[0])) {
- case ToStdout:
- if output != nil {
- _, err := io.CopyN(output, r, messageSize)
- if err != nil {
- return err
- }
- }
- case ToStderr:
- if errput != nil {
- _, err := io.CopyN(errput, r, messageSize)
- if err != nil {
- return err
- }
- }
- case ToStdin:
- if input != nil {
- _, err := io.CopyN(input, r, messageSize)
- if err != nil {
- return err
- }
- }
- case TerminalResize:
- if resize != nil {
- out := make([]byte, messageSize)
- if messageSize > 0 {
- _, err = io.ReadFull(r, out)
-
- if err != nil {
- return err
- }
- }
- // Resize events come over in bytes, need to be reserialized
- resizeEvent := remotecommand.TerminalSize{}
- if err := json.Unmarshal(out, &resizeEvent); err != nil {
- return err
- }
- resize <- resizeEvent
- }
- case Quit:
- out := make([]byte, messageSize)
- if messageSize > 0 {
- _, err = io.ReadFull(r, out)
-
- if err != nil {
- return err
- }
- }
- if execEcChan != nil {
- ecInt := binary.BigEndian.Uint32(out)
- execEcChan <- int(ecInt)
- }
- return nil
- case HangUpFromClient:
- // This sleep allows the pipes to flush themselves before tearing everything down.
- // It makes me sick to do it but after a full day I cannot put my finger on the race
- // that occurs when closing things up. It would require a significant rewrite of code
- // to make the pipes close down properly. Given that we are currently discussing a
- // rewrite of all things remote, this hardly seems worth resolving.
- //
- // reproducer: echo hello | (podman-remote run -i alpine cat)
- time.Sleep(1 * time.Second)
- return ErrClientHangup
- default:
- // Something really went wrong
- return errors.New("unknown multiplex destination")
- }
- }
-}
-
-// HangUp sends message to peer to close connection
-func HangUp(writer *bufio.Writer, ec uint32) (err error) {
- n := 0
- msg := make([]byte, 4)
-
- binary.BigEndian.PutUint32(msg, ec)
-
- writeQuit := NewVirtWriteCloser(writer, Quit)
- if n, err = writeQuit.Write(msg); err != nil {
- return
- }
-
- if n != len(msg) {
- return errors.Errorf("Failed to send complete %s message", string(msg))
- }
- return
-}
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
deleted file mode 100644
index 7cc714ea4..000000000
--- a/pkg/varlinkapi/volumes.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// +build varlink
-
-package varlinkapi
-
-import (
- "context"
- "encoding/json"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
- iopodman "github.com/containers/podman/v2/pkg/varlink"
-)
-
-// VolumeCreate creates a libpod volume based on input from a varlink connection
-func (i *VarlinkAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.VolumeCreateOpts) error {
- var volumeOptions []libpod.VolumeCreateOption
-
- if len(options.VolumeName) > 0 {
- volumeOptions = append(volumeOptions, libpod.WithVolumeName(options.VolumeName))
- }
- if len(options.Driver) > 0 {
- volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(options.Driver))
- }
- if len(options.Labels) > 0 {
- volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels))
- }
- if len(options.Options) > 0 {
- parsedOptions, err := parse.VolumeOptions(options.Options)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- volumeOptions = append(volumeOptions, parsedOptions...)
- }
- newVolume, err := i.Runtime.NewVolume(getContext(), volumeOptions...)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyVolumeCreate(newVolume.Name())
-}
-
-// VolumeRemove removes volumes by options.All or options.Volumes
-func (i *VarlinkAPI) VolumeRemove(call iopodman.VarlinkCall, options iopodman.VolumeRemoveOpts) error {
- success, failed, err := SharedRemoveVolumes(getContext(), i.Runtime, options.Volumes, options.All, options.Force)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- // Convert map[string]string to map[string]error
- errStrings := make(map[string]string)
- for k, v := range failed {
- errStrings[k] = v.Error()
- }
- return call.ReplyVolumeRemove(success, errStrings)
-}
-
-// GetVolumes returns all the volumes known to the remote system
-func (i *VarlinkAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all bool) error {
- var (
- err error
- reply []*libpod.Volume
- volumes []iopodman.Volume
- )
- if all {
- reply, err = i.Runtime.GetAllVolumes()
- } else {
- for _, v := range args {
- vol, err := i.Runtime.GetVolume(v)
- if err != nil {
- return err
- }
- reply = append(reply, vol)
- }
- }
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- // Build the iopodman.volume struct for the return
- for _, v := range reply {
- newVol := iopodman.Volume{
- Driver: v.Driver(),
- Labels: v.Labels(),
- MountPoint: v.MountPoint(),
- Name: v.Name(),
- Options: v.Options(),
- }
- volumes = append(volumes, newVol)
- }
- return call.ReplyGetVolumes(volumes)
-}
-
-// InspectVolume inspects a single volume, returning its JSON as a string.
-func (i *VarlinkAPI) InspectVolume(call iopodman.VarlinkCall, name string) error {
- vol, err := i.Runtime.LookupVolume(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- inspectOut, err := vol.Inspect()
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- inspectJSON, err := json.Marshal(inspectOut)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyInspectVolume(string(inspectJSON))
-}
-
-// VolumesPrune removes unused images via a varlink call
-func (i *VarlinkAPI) VolumesPrune(call iopodman.VarlinkCall) error {
- var (
- prunedErrors []string
- prunedNames []string
- )
- responses, err := i.Runtime.PruneVolumes(getContext())
- if err != nil {
- return call.ReplyVolumesPrune([]string{}, []string{err.Error()})
- }
- for k, v := range responses {
- if v == nil {
- prunedNames = append(prunedNames, k)
- } else {
- prunedErrors = append(prunedErrors, v.Error())
- }
- }
- return call.ReplyVolumesPrune(prunedNames, prunedErrors)
-}
-
-// Remove given set of volumes
-func SharedRemoveVolumes(ctx context.Context, runtime *libpod.Runtime, vols []string, all, force bool) ([]string, map[string]error, error) {
- var (
- toRemove []*libpod.Volume
- success []string
- failed map[string]error
- )
-
- failed = make(map[string]error)
-
- if all {
- vols, err := runtime.Volumes()
- if err != nil {
- return nil, nil, err
- }
- toRemove = vols
- } else {
- for _, v := range vols {
- vol, err := runtime.LookupVolume(v)
- if err != nil {
- failed[v] = err
- continue
- }
- toRemove = append(toRemove, vol)
- }
- }
-
- // We could parallelize this, but I haven't heard anyone complain about
- // performance here yet, so hold off.
- for _, vol := range toRemove {
- if err := runtime.RemoveVolume(ctx, vol, force); err != nil {
- failed[vol.Name()] = err
- continue
- }
- success = append(success, vol.Name())
- }
-
- return success, failed, nil
-}