summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_archive.go62
-rw-r--r--pkg/api/handlers/compat/images_build.go2
-rw-r--r--pkg/api/handlers/libpod/generate.go5
-rw-r--r--pkg/api/server/register_generate.go12
-rw-r--r--pkg/bindings/generate/generate.go11
-rw-r--r--pkg/bindings/images/build.go3
-rw-r--r--pkg/copy/copy.go68
-rw-r--r--pkg/copy/fileinfo.go56
-rw-r--r--pkg/copy/item.go13
-rw-r--r--pkg/copy/parse.go61
-rw-r--r--pkg/domain/entities/engine_container.go3
-rw-r--r--pkg/domain/entities/network.go13
-rw-r--r--pkg/domain/infra/abi/cp.go64
-rw-r--r--pkg/domain/infra/abi/generate.go54
-rw-r--r--pkg/domain/infra/abi/manifest.go2
-rw-r--r--pkg/domain/infra/abi/network.go20
-rw-r--r--pkg/domain/infra/abi/system.go76
-rw-r--r--pkg/domain/infra/tunnel/containers.go3
-rw-r--r--pkg/domain/infra/tunnel/generate.go4
-rw-r--r--pkg/domain/infra/tunnel/network.go4
-rw-r--r--pkg/specgen/generate/config_linux.go23
-rw-r--r--pkg/specgen/generate/kube/kube.go5
-rw-r--r--pkg/specgen/generate/kube/volume.go2
-rw-r--r--pkg/specgen/generate/ports.go12
-rw-r--r--pkg/specgen/generate/security.go2
25 files changed, 394 insertions, 186 deletions
diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go
index 223eb2cd5..d8197415c 100644
--- a/pkg/api/handlers/compat/containers_archive.go
+++ b/pkg/api/handlers/compat/containers_archive.go
@@ -1,13 +1,8 @@
package compat
import (
- "bytes"
- "encoding/base64"
- "encoding/json"
"fmt"
"net/http"
- "os"
- "time"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
@@ -15,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/copy"
"github.com/gorilla/schema"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
func Archive(w http.ResponseWriter, r *http.Request) {
@@ -71,12 +67,12 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
return
}
- statHeader, err := fileInfoToDockerStats(info)
+ statHeader, err := copy.EncodeFileInfo(info)
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
- w.Header().Add("X-Docker-Container-Path-Stat", statHeader)
+ w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader)
// Our work is done when the user is interested in the header only.
if r.Method == http.MethodHead {
@@ -91,47 +87,16 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
return
}
- w.WriteHeader(http.StatusOK)
- if err := copy.Copy(&source, &destination, false); err != nil {
+ copier, err := copy.GetCopier(&source, &destination, false)
+ if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
-}
-
-func fileInfoToDockerStats(info *copy.FileInfo) (string, error) {
- dockerStats := struct {
- Name string `json:"name"`
- Size int64 `json:"size"`
- Mode os.FileMode `json:"mode"`
- ModTime time.Time `json:"mtime"`
- LinkTarget string `json:"linkTarget"`
- }{
- Name: info.Name,
- Size: info.Size,
- Mode: info.Mode,
- ModTime: info.ModTime,
- LinkTarget: info.LinkTarget,
- }
-
- jsonBytes, err := json.Marshal(&dockerStats)
- if err != nil {
- return "", errors.Wrap(err, "failed to serialize file stats")
- }
-
- buff := bytes.NewBuffer(make([]byte, 0, 128))
- base64encoder := base64.NewEncoder(base64.StdEncoding, buff)
-
- _, err = base64encoder.Write(jsonBytes)
- if err != nil {
- return "", err
- }
-
- err = base64encoder.Close()
- if err != nil {
- return "", err
+ w.WriteHeader(http.StatusOK)
+ if err := copier.Copy(); err != nil {
+ logrus.Errorf("Error during copy: %v", err)
+ return
}
-
- return buff.String(), nil
}
func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
@@ -170,9 +135,14 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder,
return
}
- w.WriteHeader(http.StatusOK)
- if err := copy.Copy(&source, &destination, false); err != nil {
+ copier, err := copy.GetCopier(&source, &destination, false)
+ if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
+ w.WriteHeader(http.StatusOK)
+ if err := copier.Copy(); err != nil {
+ logrus.Errorf("Error during copy: %v", err)
+ return
+ }
}
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index 43478c1d3..415ff85cd 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -71,6 +71,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
ForceRm bool `schema:"forcerm"`
HTTPProxy bool `schema:"httpproxy"`
Labels string `schema:"labels"`
+ Layers bool `schema:"layers"`
MemSwap int64 `schema:"memswap"`
Memory int64 `schema:"memory"`
NetworkMode string `schema:"networkmode"`
@@ -165,6 +166,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Registry: query.Registry,
IgnoreUnrecognizedInstructions: true,
Quiet: query.Quiet,
+ Layers: query.Layers,
Isolation: buildah.IsolationChroot,
Compression: archive.Gzip,
Args: buildArgs,
diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go
index 33bb75391..b3b8c1f16 100644
--- a/pkg/api/handlers/libpod/generate.go
+++ b/pkg/api/handlers/libpod/generate.go
@@ -60,7 +60,8 @@ func GenerateKube(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Service bool `schema:"service"`
+ Names []string `schema:"names"`
+ Service bool `schema:"service"`
}{
// Defaults would go here.
}
@@ -73,7 +74,7 @@ func GenerateKube(w http.ResponseWriter, r *http.Request) {
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.GenerateKubeOptions{Service: query.Service}
- report, err := containerEngine.GenerateKube(r.Context(), utils.GetName(r), options)
+ report, err := containerEngine.GenerateKube(r.Context(), query.Names, options)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error generating YAML"))
return
diff --git a/pkg/api/server/register_generate.go b/pkg/api/server/register_generate.go
index 60e5b03f7..bce5484ab 100644
--- a/pkg/api/server/register_generate.go
+++ b/pkg/api/server/register_generate.go
@@ -70,7 +70,7 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error {
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/generate/{name:.*}/systemd"), s.APIHandler(libpod.GenerateSystemd)).Methods(http.MethodGet)
- // swagger:operation GET /libpod/generate/{name:.*}/kube libpod libpodGenerateKube
+ // swagger:operation GET /libpod/generate/kube libpod libpodGenerateKube
// ---
// tags:
// - containers
@@ -78,9 +78,11 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error {
// summary: Generate a Kubernetes YAML file.
// description: Generate Kubernetes YAML based on a pod or container.
// parameters:
- // - in: path
- // name: name:.*
- // type: string
+ // - in: query
+ // name: names
+ // type: array
+ // items:
+ // type: string
// required: true
// description: Name or ID of the container or pod.
// - in: query
@@ -98,6 +100,6 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error {
// format: binary
// 500:
// $ref: "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/generate/{name:.*}/kube"), s.APIHandler(libpod.GenerateKube)).Methods(http.MethodGet)
+ r.HandleFunc(VersionedPath("/libpod/generate/kube"), s.APIHandler(libpod.GenerateKube)).Methods(http.MethodGet)
return nil
}
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index dde1cc29c..8d0146ec1 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -2,6 +2,7 @@ package generate
import (
"context"
+ "errors"
"net/http"
"net/url"
"strconv"
@@ -37,15 +38,21 @@ func Systemd(ctx context.Context, nameOrID string, options entities.GenerateSyst
return report, response.Process(&report.Units)
}
-func Kube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+func Kube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
+ if len(nameOrIDs) < 1 {
+ return nil, errors.New("must provide the name or ID of one container or pod")
+ }
params := url.Values{}
+ for _, name := range nameOrIDs {
+ params.Add("names", name)
+ }
params.Set("service", strconv.FormatBool(options.Service))
- response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/kube", params, nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/generate/kube", params, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index 815ab4e86..d34ab87d9 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -41,6 +41,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
if options.NoCache {
params.Set("nocache", "1")
}
+ if options.Layers {
+ params.Set("layers", "1")
+ }
// TODO cachefrom
if options.PullPolicy == buildah.PullAlways {
params.Set("pull", "1")
diff --git a/pkg/copy/copy.go b/pkg/copy/copy.go
index 0e68eb450..13893deb2 100644
--- a/pkg/copy/copy.go
+++ b/pkg/copy/copy.go
@@ -25,31 +25,61 @@ import (
//
// ****************************************************************************
-// Copy the source item to destination. Use extract to untar the source if
-// it's a tar archive.
-func Copy(source *CopyItem, destination *CopyItem, extract bool) error {
+// Copier copies data from a source to a destination CopyItem.
+type Copier struct {
+ copyFunc func() error
+ cleanUpFuncs []deferFunc
+}
+
+// cleanUp releases resources the Copier may hold open.
+func (c *Copier) cleanUp() {
+ for _, f := range c.cleanUpFuncs {
+ f()
+ }
+}
+
+// Copy data from a source to a destination CopyItem.
+func (c *Copier) Copy() error {
+ defer c.cleanUp()
+ return c.copyFunc()
+}
+
+// GetCopiers returns a Copier to copy the source item to destination. Use
+// extract to untar the source if it's a tar archive.
+func GetCopier(source *CopyItem, destination *CopyItem, extract bool) (*Copier, error) {
+ copier := &Copier{}
+
// First, do the man-page dance. See podman-cp(1) for details.
if err := enforceCopyRules(source, destination); err != nil {
- return err
+ return nil, err
}
// Destination is a stream (e.g., stdout or an http body).
if destination.info.IsStream {
// Source is a stream (e.g., stdin or an http body).
if source.info.IsStream {
- _, err := io.Copy(destination.writer, source.reader)
- return err
+ copier.copyFunc = func() error {
+ _, err := io.Copy(destination.writer, source.reader)
+ return err
+ }
+ return copier, nil
}
root, glob, err := source.buildahGlobs()
if err != nil {
- return err
+ return nil, err
}
- return buildahCopiah.Get(root, "", source.getOptions(), []string{glob}, destination.writer)
+ copier.copyFunc = func() error {
+ return buildahCopiah.Get(root, "", source.getOptions(), []string{glob}, destination.writer)
+ }
+ return copier, nil
}
// Destination is either a file or a directory.
if source.info.IsStream {
- return buildahCopiah.Put(destination.root, destination.resolved, source.putOptions(), source.reader)
+ copier.copyFunc = func() error {
+ return buildahCopiah.Put(destination.root, destination.resolved, source.putOptions(), source.reader)
+ }
+ return copier, nil
}
tarOptions := &archive.TarOptions{
@@ -71,33 +101,36 @@ func Copy(source *CopyItem, destination *CopyItem, extract bool) error {
var tarReader io.ReadCloser
if extract && archive.IsArchivePath(source.resolved) {
if !destination.info.IsDir {
- return errors.Errorf("cannot extract archive %q to file %q", source.original, destination.original)
+ return nil, errors.Errorf("cannot extract archive %q to file %q", source.original, destination.original)
}
reader, err := os.Open(source.resolved)
if err != nil {
- return err
+ return nil, err
}
- defer reader.Close()
+ copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() })
// The stream from stdin may be compressed (e.g., via gzip).
decompressedStream, err := archive.DecompressStream(reader)
if err != nil {
- return err
+ return nil, err
}
- defer decompressedStream.Close()
+ copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { decompressedStream.Close() })
tarReader = decompressedStream
} else {
reader, err := archive.TarWithOptions(source.resolved, tarOptions)
if err != nil {
- return err
+ return nil, err
}
- defer reader.Close()
+ copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() })
tarReader = reader
}
- return buildahCopiah.Put(root, dir, source.putOptions(), tarReader)
+ copier.copyFunc = func() error {
+ return buildahCopiah.Put(root, dir, source.putOptions(), tarReader)
+ }
+ return copier, nil
}
// enforceCopyRules enforces the rules for copying from a source to a
@@ -114,7 +147,6 @@ func enforceCopyRules(source, destination *CopyItem) error {
return nil
}
- // Source is a *stream*.
if source.info.IsStream {
if !(destination.info.IsDir || destination.info.IsStream) {
return errors.New("destination must be a directory or stream when copying from a stream")
diff --git a/pkg/copy/fileinfo.go b/pkg/copy/fileinfo.go
new file mode 100644
index 000000000..08b4eb377
--- /dev/null
+++ b/pkg/copy/fileinfo.go
@@ -0,0 +1,56 @@
+package copy
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "net/http"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/pkg/errors"
+)
+
+// XDockerContainerPathStatHeader is the *key* in http headers pointing to the
+// base64 encoded JSON payload of stating a path in a container.
+const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat"
+
+// FileInfo describes a file or directory and is returned by
+// (*CopyItem).Stat().
+type FileInfo struct {
+ Name string `json:"name"`
+ Size int64 `json:"size"`
+ Mode os.FileMode `json:"mode"`
+ ModTime time.Time `json:"mtime"`
+ IsDir bool `json:"isDir"`
+ IsStream bool `json:"isStream"`
+ LinkTarget string `json:"linkTarget"`
+}
+
+// EncodeFileInfo serializes the specified FileInfo as a base64 encoded JSON
+// payload. Intended for Docker compat.
+func EncodeFileInfo(info *FileInfo) (string, error) {
+ buf, err := json.Marshal(&info)
+ if err != nil {
+ return "", errors.Wrap(err, "failed to serialize file stats")
+ }
+ return base64.URLEncoding.EncodeToString(buf), nil
+}
+
+// ExtractFileInfoFromHeader extracts a base64 encoded JSON payload of a
+// FileInfo in the http header. If no such header entry is found, nil is
+// returned. Intended for Docker compat.
+func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) {
+ rawData := header.Get(XDockerContainerPathStatHeader)
+ if len(rawData) == 0 {
+ return nil, nil
+ }
+
+ info := FileInfo{}
+ base64Decoder := base64.NewDecoder(base64.URLEncoding, strings.NewReader(rawData))
+ if err := json.NewDecoder(base64Decoder).Decode(&info); err != nil {
+ return nil, err
+ }
+
+ return &info, nil
+}
diff --git a/pkg/copy/item.go b/pkg/copy/item.go
index db6bca610..df8bf30b9 100644
--- a/pkg/copy/item.go
+++ b/pkg/copy/item.go
@@ -5,7 +5,6 @@ import (
"os"
"path/filepath"
"strings"
- "time"
buildahCopiah "github.com/containers/buildah/copier"
"github.com/containers/buildah/pkg/chrootuser"
@@ -75,18 +74,6 @@ type CopyItem struct {
// deferFunc allows for returning functions that must be deferred at call sites.
type deferFunc func()
-// FileInfo describes a file or directory and is returned by
-// (*CopyItem).Stat().
-type FileInfo struct {
- Name string `json:"name"`
- Size int64 `json:"size"`
- Mode os.FileMode `json:"mode"`
- ModTime time.Time `json:"mtime"`
- IsDir bool `json:"isDir"`
- IsStream bool `json:"isStream"`
- LinkTarget string `json:"linkTarget"`
-}
-
// Stat returns the FileInfo.
func (item *CopyItem) Stat() (*FileInfo, error) {
return &item.info, item.statError
diff --git a/pkg/copy/parse.go b/pkg/copy/parse.go
new file mode 100644
index 000000000..39e0e1547
--- /dev/null
+++ b/pkg/copy/parse.go
@@ -0,0 +1,61 @@
+package copy
+
+import (
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+// ParseSourceAndDestination parses the source and destination input into a
+// possibly specified container and path. The input format is described in
+// podman-cp(1) as "[nameOrID:]path". Colons in paths are supported as long
+// they start with a dot or slash.
+//
+// It returns, in order, the source container and path, followed by the
+// destination container and path, and an error. Note that exactly one
+// container must be specified.
+func ParseSourceAndDestination(source, destination string) (string, string, string, string, error) {
+ sourceContainer, sourcePath := parseUserInput(source)
+ destContainer, destPath := parseUserInput(destination)
+
+ numContainers := 0
+ if len(sourceContainer) > 0 {
+ numContainers++
+ }
+ if len(destContainer) > 0 {
+ numContainers++
+ }
+
+ if numContainers != 1 {
+ return "", "", "", "", errors.Errorf("invalid arguments %q, %q: exactly 1 container expected but %d specified", source, destination, numContainers)
+ }
+
+ if len(sourcePath) == 0 || len(destPath) == 0 {
+ return "", "", "", "", errors.Errorf("invalid arguments %q, %q: you must specify paths", source, destination)
+ }
+
+ return sourceContainer, sourcePath, destContainer, destPath, nil
+}
+
+// parseUserInput parses the input string and returns, if specified, the name
+// or ID of the container and the path. The input format is described in
+// podman-cp(1) as "[nameOrID:]path". Colons in paths are supported as long
+// they start with a dot or slash.
+func parseUserInput(input string) (container string, path string) {
+ if len(input) == 0 {
+ return
+ }
+ path = input
+
+ // If the input starts with a dot or slash, it cannot refer to a
+ // container.
+ if input[0] == '.' || input[0] == '/' {
+ return
+ }
+
+ if spl := strings.SplitN(path, ":", 2); len(spl) == 2 {
+ container = spl[0]
+ path = spl[1]
+ }
+ return
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index e1f40e307..5ad475133 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -46,7 +46,7 @@ type ContainerEngine interface {
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
Events(ctx context.Context, opts EventsOptions) error
GenerateSystemd(ctx context.Context, nameOrID string, opts GenerateSystemdOptions) (*GenerateSystemdReport, error)
- GenerateKube(ctx context.Context, nameOrID string, opts GenerateKubeOptions) (*GenerateKubeReport, error)
+ GenerateKube(ctx context.Context, nameOrIDs []string, opts GenerateKubeOptions) (*GenerateKubeReport, error)
SystemPrune(ctx context.Context, options SystemPruneOptions) (*SystemPruneReport, error)
HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
@@ -55,6 +55,7 @@ type ContainerEngine interface {
NetworkDisconnect(ctx context.Context, networkname string, options NetworkDisconnectOptions) error
NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
+ NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go
index 65a110fd9..b76bfcac7 100644
--- a/pkg/domain/entities/network.go
+++ b/pkg/domain/entities/network.go
@@ -22,6 +22,19 @@ type NetworkListReport struct {
// NetworkInspectReport describes the results from inspect networks
type NetworkInspectReport map[string]interface{}
+// NetworkReloadOptions describes options for reloading container network
+// configuration.
+type NetworkReloadOptions struct {
+ All bool
+ Latest bool
+}
+
+// NetworkReloadReport describes the results of reloading a container network.
+type NetworkReloadReport struct {
+ Id string
+ Err error
+}
+
// NetworkRmOptions describes options for removing networks
type NetworkRmOptions struct {
Force bool
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
index 9409df743..362053cce 100644
--- a/pkg/domain/infra/abi/cp.go
+++ b/pkg/domain/infra/abi/cp.go
@@ -2,46 +2,53 @@ package abi
import (
"context"
- "strings"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/pkg/copy"
"github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/pkg/errors"
)
func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
- srcCtr, srcPath := parsePath(ic.Libpod, source)
- destCtr, destPath := parsePath(ic.Libpod, dest)
-
- if srcCtr != nil && destCtr != nil {
- return errors.Errorf("invalid arguments %q, %q: you must use just one container", source, dest)
+ // Parse user input.
+ sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(source, dest)
+ if err != nil {
+ return err
}
- if srcCtr == nil && destCtr == nil {
- return errors.Errorf("invalid arguments %q, %q: you must specify one container", source, dest)
+
+ // Look up containers.
+ var sourceContainer, destContainer *libpod.Container
+ if len(sourceContainerStr) > 0 {
+ sourceContainer, err = ic.Libpod.LookupContainer(sourceContainerStr)
+ if err != nil {
+ return err
+ }
}
- if len(srcPath) == 0 || len(destPath) == 0 {
- return errors.Errorf("invalid arguments %q, %q: you must specify paths", source, dest)
+ if len(destContainerStr) > 0 {
+ destContainer, err = ic.Libpod.LookupContainer(destContainerStr)
+ if err != nil {
+ return err
+ }
}
var sourceItem, destinationItem copy.CopyItem
- var err error
- // Copy from the container to the host.
- if srcCtr != nil {
- sourceItem, err = copy.CopyItemForContainer(srcCtr, srcPath, options.Pause, true)
+
+ // Source ... container OR host.
+ if sourceContainer != nil {
+ sourceItem, err = copy.CopyItemForContainer(sourceContainer, sourcePath, options.Pause, true)
defer sourceItem.CleanUp()
if err != nil {
return err
}
} else {
- sourceItem, err = copy.CopyItemForHost(srcPath, true)
+ sourceItem, err = copy.CopyItemForHost(sourcePath, true)
if err != nil {
return err
}
}
- if destCtr != nil {
- destinationItem, err = copy.CopyItemForContainer(destCtr, destPath, options.Pause, false)
+ // Destination ... container OR host.
+ if destContainer != nil {
+ destinationItem, err = copy.CopyItemForContainer(destContainer, destPath, options.Pause, false)
defer destinationItem.CleanUp()
if err != nil {
return err
@@ -55,22 +62,9 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string,
}
// Copy from the host to the container.
- return copy.Copy(&sourceItem, &destinationItem, options.Extract)
-}
-
-func parsePath(runtime *libpod.Runtime, path string) (*libpod.Container, string) {
- if len(path) == 0 {
- return nil, ""
- }
- if path[0] == '.' || path[0] == '/' { // A path cannot point to a container.
- return nil, path
- }
- pathArr := strings.SplitN(path, ":", 2)
- if len(pathArr) == 2 {
- ctr, err := runtime.LookupContainer(pathArr[0])
- if err == nil {
- return ctr, pathArr[1]
- }
+ copier, err := copy.GetCopier(&sourceItem, &destinationItem, options.Extract)
+ if err != nil {
+ return err
}
- return nil, path
+ return copier.Copy()
}
diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go
index 79bf2291e..79f55e2bd 100644
--- a/pkg/domain/infra/abi/generate.go
+++ b/pkg/domain/infra/abi/generate.go
@@ -41,28 +41,48 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
return &entities.GenerateSystemdReport{Units: units}, nil
}
-func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
var (
- pod *libpod.Pod
+ pods []*libpod.Pod
podYAML *k8sAPI.Pod
err error
- ctr *libpod.Container
+ ctrs []*libpod.Container
servicePorts []k8sAPI.ServicePort
serviceYAML k8sAPI.Service
)
- // Get the container in question.
- ctr, err = ic.Libpod.LookupContainer(nameOrID)
- if err != nil {
- pod, err = ic.Libpod.LookupPod(nameOrID)
+ for _, nameOrID := range nameOrIDs {
+ // Get the container in question
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
if err != nil {
- return nil, err
+ pod, err := ic.Libpod.LookupPod(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+ pods = append(pods, pod)
+ if len(pods) > 1 {
+ return nil, errors.New("can only generate single pod at a time")
+ }
+ } else {
+ if len(ctr.Dependencies()) > 0 {
+ return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
+ }
+ // we cannot deal with ctrs already in a pod
+ if len(ctr.PodID()) > 0 {
+ return nil, errors.Errorf("container %s is associated with pod %s: use generate on the pod itself", ctr.ID(), ctr.PodID())
+ }
+ ctrs = append(ctrs, ctr)
}
- podYAML, servicePorts, err = pod.GenerateForKube()
+ }
+
+ // check our inputs
+ if len(pods) > 0 && len(ctrs) > 0 {
+ return nil, errors.New("cannot generate pods and containers at the same time")
+ }
+
+ if len(pods) == 1 {
+ podYAML, servicePorts, err = pods[0].GenerateForKube()
} else {
- if len(ctr.Dependencies()) > 0 {
- return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
- }
- podYAML, err = ctr.GenerateForKube()
+ podYAML, err = libpod.GenerateForKube(ctrs)
}
if err != nil {
return nil, err
@@ -72,7 +92,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, op
serviceYAML = libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts)
}
- content, err := generateKubeOutput(podYAML, &serviceYAML)
+ content, err := generateKubeOutput(podYAML, &serviceYAML, options.Service)
if err != nil {
return nil, err
}
@@ -80,7 +100,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, op
return &entities.GenerateKubeReport{Reader: bytes.NewReader(content)}, nil
}
-func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service) ([]byte, error) {
+func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service, hasService bool) ([]byte, error) {
var (
output []byte
marshalledPod []byte
@@ -93,7 +113,7 @@ func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service) ([]byt
return nil, err
}
- if serviceYAML != nil {
+ if hasService {
marshalledService, err = yaml.Marshal(serviceYAML)
if err != nil {
return nil, err
@@ -114,7 +134,7 @@ func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service) ([]byt
output = append(output, []byte(fmt.Sprintf(header, podmanVersion.Version))...)
output = append(output, marshalledPod...)
- if serviceYAML != nil {
+ if hasService {
output = append(output, []byte("---\n")...)
output = append(output, marshalledService...)
}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index ad7128b42..600d64b1d 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -54,7 +54,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
}
return buf, nil
// no return if local image is not a list of images type
- // continue on getting valid manifest through remote serice
+ // continue on getting valid manifest through remote service
} else if errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported {
return nil, errors.Wrapf(err, "loading manifest %q", name)
}
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 6a219edd5..e5ecf5c72 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -60,6 +60,26 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
return rawCNINetworks, errs, nil
}
+func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, options entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) {
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+
+ reports := make([]*entities.NetworkReloadReport, 0, len(ctrs))
+ for _, ctr := range ctrs {
+ report := new(entities.NetworkReloadReport)
+ report.Id = ctr.ID()
+ report.Err = ctr.ReloadNetwork()
+ if options.All && errors.Cause(report.Err) == define.ErrCtrStateInvalid {
+ continue
+ }
+ reports = append(reports, report)
+ }
+
+ return reports, nil
+}
+
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
reports := []*entities.NetworkRmReport{}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index ec2532bea..7ed58092b 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -168,37 +168,61 @@ func checkInput() error { // nolint:deadcode,unused
// SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
var systemPruneReport = new(entities.SystemPruneReport)
- podPruneReport, err := ic.prunePodHelper(ctx)
- if err != nil {
- return nil, err
- }
- systemPruneReport.PodPruneReport = podPruneReport
-
- containerPruneReport, err := ic.pruneContainersHelper(nil)
- if err != nil {
- return nil, err
- }
- systemPruneReport.ContainerPruneReport = containerPruneReport
-
- results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, nil)
- if err != nil {
- return nil, err
- }
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
+ found := true
+ for found {
+ found = false
+ podPruneReport, err := ic.prunePodHelper(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if len(podPruneReport) > 0 {
+ found = true
+ }
+ systemPruneReport.PodPruneReport = append(systemPruneReport.PodPruneReport, podPruneReport...)
+ containerPruneReport, err := ic.pruneContainersHelper(nil)
+ if err != nil {
+ return nil, err
+ }
+ if len(containerPruneReport.ID) > 0 {
+ found = true
+ }
+ if systemPruneReport.ContainerPruneReport == nil {
+ systemPruneReport.ContainerPruneReport = containerPruneReport
+ } else {
+ for name, val := range containerPruneReport.ID {
+ systemPruneReport.ContainerPruneReport.ID[name] = val
+ }
+ }
- systemPruneReport.ImagePruneReport = &report
+ results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, nil)
- if options.Volume {
- volumePruneReport, err := ic.pruneVolumesHelper(ctx)
if err != nil {
return nil, err
}
- systemPruneReport.VolumePruneReport = volumePruneReport
+ if len(results) > 0 {
+ found = true
+ }
+
+ if systemPruneReport.ImagePruneReport == nil {
+ systemPruneReport.ImagePruneReport = &entities.ImagePruneReport{
+ Report: entities.Report{
+ Id: results,
+ Err: nil,
+ },
+ }
+ } else {
+ systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
+ }
+ if options.Volume {
+ volumePruneReport, err := ic.pruneVolumesHelper(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if len(volumePruneReport) > 0 {
+ found = true
+ }
+ systemPruneReport.VolumePruneReport = append(systemPruneReport.VolumePruneReport, volumePruneReport...)
+ }
}
return systemPruneReport, nil
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 3584668c7..e65fef0a4 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -732,7 +732,8 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
}
func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
- return errors.New("not implemented")
+ return nil
+ // return containers.Copy(ic.ClientCxt, source, dest, options)
}
// Shutdown Libpod engine
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
index 966f707b1..ebbfa143f 100644
--- a/pkg/domain/infra/tunnel/generate.go
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -11,6 +11,6 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
return generate.Systemd(ic.ClientCxt, nameOrID, options)
}
-func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
- return generate.Kube(ic.ClientCxt, nameOrID, options)
+func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+ return generate.Kube(ic.ClientCxt, nameOrIDs, options)
}
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 10ae03045..4845980f6 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -35,6 +35,10 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
return reports, errs, nil
}
+func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, options entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) {
+ return nil, errors.New("not implemented")
+}
+
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
reports := make([]*entities.NetworkRmReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index 1808f99b8..e0b039fb7 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -167,22 +167,23 @@ func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, mask, unmask
g.AddLinuxMaskedPaths(mp)
}
}
+ for _, rp := range []string{
+ "/proc/asound",
+ "/proc/bus",
+ "/proc/fs",
+ "/proc/irq",
+ "/proc/sys",
+ "/proc/sysrq-trigger",
+ } {
+ if !util.StringInSlice(rp, unmask) {
+ g.AddLinuxReadonlyPaths(rp)
+ }
+ }
}
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)
- }
}
// mask the paths provided by the user
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 5f72d28bb..5cc7891ac 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -148,6 +148,11 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
// Environment Variables
envs := map[string]string{}
+ for _, env := range imageData.Config.Env {
+ keyval := strings.Split(env, "=")
+ envs[keyval[0]] = keyval[1]
+ }
+
for _, env := range containerYAML.Env {
value := envVarValue(env, configMaps)
diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go
index 2ef0f4c23..bb8edabb7 100644
--- a/pkg/specgen/generate/kube/volume.go
+++ b/pkg/specgen/generate/kube/volume.go
@@ -103,7 +103,7 @@ func VolumeFromSource(volumeSource v1.VolumeSource) (*KubeVolume, error) {
} else if volumeSource.PersistentVolumeClaim != nil {
return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim)
} else {
- return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the conly supported VolumeSource")
+ return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the only supported VolumeSource")
}
}
diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go
index 5c13c95b2..83ded059f 100644
--- a/pkg/specgen/generate/ports.go
+++ b/pkg/specgen/generate/ports.go
@@ -107,7 +107,11 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
var index uint16
for index = 0; index < len; index++ {
cPort := containerPort + index
- hPort := hostPort + index
+ hPort := hostPort
+ // Only increment host port if it's not 0.
+ if hostPort != 0 {
+ hPort += index
+ }
if cPort == 0 {
return nil, nil, nil, errors.Errorf("container port cannot be 0")
@@ -162,8 +166,8 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
tempMappings,
tempMapping{
mapping: cniPort,
- startOfRange: port.Range > 0 && index == 0,
- isInRange: port.Range > 0,
+ startOfRange: port.Range > 1 && index == 0,
+ isInRange: port.Range > 1,
},
)
}
@@ -183,7 +187,7 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
for _, tmp := range tempMappings {
p := tmp.mapping
- if p.HostPort != 0 && !tmp.isInRange {
+ if p.HostPort != 0 {
remadeMappings = append(remadeMappings, p)
continue
}
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index dee140282..56947ff24 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -141,7 +141,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
} else {
- userCaps, err := capabilities.NormalizeCapabilities(s.CapAdd)
+ userCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
if err != nil {
return errors.Wrapf(err, "capabilities requested by user are not valid: %q", strings.Join(s.CapAdd, ","))
}