summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/libpod/images.go7
-rw-r--r--pkg/api/handlers/libpod/networks.go14
-rw-r--r--pkg/api/server/idle/tracker.go5
-rw-r--r--pkg/bindings/connection.go16
-rw-r--r--pkg/bindings/test/images_test.go2
-rw-r--r--pkg/domain/entities/containers.go1
-rw-r--r--pkg/domain/entities/engine_container.go4
-rw-r--r--pkg/domain/entities/network.go5
-rw-r--r--pkg/domain/entities/types.go2
-rw-r--r--pkg/domain/entities/volumes.go4
-rw-r--r--pkg/domain/infra/abi/containers.go7
-rw-r--r--pkg/domain/infra/abi/cp.go8
-rw-r--r--pkg/domain/infra/abi/images.go10
-rw-r--r--pkg/domain/infra/abi/images_list.go16
-rw-r--r--pkg/domain/infra/abi/manifest.go23
-rw-r--r--pkg/domain/infra/abi/network.go15
-rw-r--r--pkg/domain/infra/abi/play.go13
-rw-r--r--pkg/domain/infra/abi/system.go2
-rw-r--r--pkg/domain/infra/abi/terminal/sigproxy_linux.go8
-rw-r--r--pkg/domain/infra/abi/volumes.go19
-rw-r--r--pkg/domain/infra/tunnel/containers.go6
-rw-r--r--pkg/domain/infra/tunnel/network.go20
-rw-r--r--pkg/domain/infra/tunnel/volumes.go22
-rw-r--r--pkg/spec/parse.go2
-rw-r--r--pkg/spec/storage.go2
-rw-r--r--pkg/specgen/generate/config_linux.go14
-rw-r--r--pkg/specgen/generate/container_create.go15
-rw-r--r--pkg/specgen/generate/namespaces.go13
-rw-r--r--pkg/specgen/generate/security.go10
-rw-r--r--pkg/specgen/generate/validate.go65
-rw-r--r--pkg/specgen/specgen.go16
-rw-r--r--pkg/terminal/util.go6
-rw-r--r--pkg/util/mountOpts.go2
-rw-r--r--pkg/util/utils.go38
-rw-r--r--pkg/util/utils_test.go20
35 files changed, 328 insertions, 104 deletions
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 598a46abe..55264b3b6 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -44,11 +44,16 @@ func ImageExists(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
- _, err := runtime.ImageRuntime().NewFromLocal(name)
+ ir := abi.ImageEngine{Libpod: runtime}
+ report, err := ir.Exists(r.Context(), name)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
return
}
+ if !report.Value {
+ utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(nil, "failed to find image %s", name))
+ return
+ }
utils.WriteResponse(w, http.StatusNoContent, "")
}
diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go
index b7e2b3988..9f6103c45 100644
--- a/pkg/api/handlers/libpod/networks.go
+++ b/pkg/api/handlers/libpod/networks.go
@@ -113,15 +113,15 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
return
}
name := utils.GetName(r)
- options := entities.NetworkInspectOptions{}
+ options := entities.InspectOptions{}
ic := abi.ContainerEngine{Libpod: runtime}
- reports, err := ic.NetworkInspect(r.Context(), []string{name}, options)
+ reports, errs, err := ic.NetworkInspect(r.Context(), []string{name}, options)
+ // If the network cannot be found, we return a 404.
+ if len(errs) > 0 {
+ utils.Error(w, "Something went wrong", http.StatusNotFound, define.ErrNoSuchNetwork)
+ return
+ }
if err != nil {
- // If the network cannot be found, we return a 404.
- if errors.Cause(err) == define.ErrNoSuchNetwork {
- utils.Error(w, "Something went wrong", http.StatusNotFound, err)
- return
- }
utils.InternalServerError(w, err)
return
}
diff --git a/pkg/api/server/idle/tracker.go b/pkg/api/server/idle/tracker.go
index 50e41b7bf..687ebd7d4 100644
--- a/pkg/api/server/idle/tracker.go
+++ b/pkg/api/server/idle/tracker.go
@@ -41,11 +41,12 @@ func (t *Tracker) ConnState(conn net.Conn, state http.ConnState) {
logrus.Debugf("IdleTracker %p:%v %dm+%dh/%dt connection(s)", conn, state, len(t.managed), t.hijacked, t.TotalConnections())
switch state {
- case http.StateNew, http.StateActive:
+ case http.StateNew:
+ t.total++
+ case http.StateActive:
// stop the API timer when the server transitions any connection to an "active" state
t.managed[conn] = struct{}{}
t.timer.Stop()
- t.total++
case http.StateHijacked:
// hijacked connections should call Close() when finished.
// Note: If a handler hijack's a connection and then doesn't Close() it,
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index 3a7662c41..31435ae91 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -214,19 +214,23 @@ func sshClient(_url *url.URL, secure bool, passPhrase string, identity string) (
authMethods = append(authMethods, ssh.Password(string(pass)))
}
+ port := _url.Port()
+ if port == "" {
+ port = "22"
+ }
+
callback := ssh.InsecureIgnoreHostKey()
if secure {
- key := terminal.HostKey(_url.Hostname())
+ host := _url.Hostname()
+ if port != "22" {
+ host = fmt.Sprintf("[%s]:%s", host, port)
+ }
+ key := terminal.HostKey(host)
if key != nil {
callback = ssh.FixedHostKey(key)
}
}
- port := _url.Port()
- if port == "" {
- port = "22"
- }
-
bastion, err := ssh.Dial("tcp",
net.JoinHostPort(_url.Hostname(), port),
&ssh.ClientConfig{
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 681855293..7d9415f91 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -166,7 +166,7 @@ var _ = Describe("Podman images", func() {
// Adding one more image. There Should be no errors in the response.
// And the count should be three now.
- bt.Pull("busybox:glibc")
+ bt.Pull("testimage:20200929")
imageSummary, err = images.List(bt.conn, nil, nil)
Expect(err).To(BeNil())
Expect(len(imageSummary)).To(Equal(3))
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 46b169284..3fd7c79f4 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -294,6 +294,7 @@ type ContainerListOptions struct {
// ContainerRunOptions describes the options needed
// to run a container from the CLI
type ContainerRunOptions struct {
+ CIDFile string
Detach bool
DetachKeys string
ErrorStream *os.File
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index a20d3b404..8ab72dbd8 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -51,7 +51,7 @@ type ContainerEngine interface {
HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (*NetworkCreateReport, error)
- NetworkInspect(ctx context.Context, namesOrIds []string, options NetworkInspectOptions) ([]NetworkInspectReport, error)
+ NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
@@ -76,7 +76,7 @@ type ContainerEngine interface {
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 VolumeInspectOptions) ([]*VolumeInspectReport, error)
+ VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
VolumePrune(ctx context.Context) ([]*VolumePruneReport, error)
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)
diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go
index 9beeeb042..0bab672a7 100644
--- a/pkg/domain/entities/network.go
+++ b/pkg/domain/entities/network.go
@@ -18,11 +18,6 @@ type NetworkListReport struct {
*libcni.NetworkConfigList
}
-// NetworkInspectOptions describes options for inspect networks
-type NetworkInspectOptions struct {
- Format string
-}
-
// NetworkInspectReport describes the results from inspect networks
type NetworkInspectReport map[string]interface{}
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index 5fdd8afcb..d8ad2d891 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -56,6 +56,8 @@ type InspectOptions struct {
Size bool `json:",omitempty"`
// Type -- return JSON for specified type.
Type string `json:",omitempty"`
+ // All -- inspect all
+ All bool `json:",omitempty"`
}
// All API and CLI diff commands and diff sub-commands use the same options
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index fb8466d04..1bc1e4301 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -105,10 +105,6 @@ type VolumeRmReport struct {
Id string //nolint
}
-type VolumeInspectOptions struct {
- All bool
-}
-
type VolumeInspectReport struct {
*VolumeConfigResponse
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 60dbbce6c..98b886845 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -29,6 +29,7 @@ import (
"github.com/containers/podman/v2/pkg/signal"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/podman/v2/pkg/specgen/generate"
+ "github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -846,6 +847,12 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
return nil, err
}
+ if opts.CIDFile != "" {
+ if err := util.CreateCidFile(opts.CIDFile, ctr.ID()); err != nil {
+ return nil, err
+ }
+ }
+
var joinPod bool
if len(ctr.PodID()) > 0 {
joinPod = true
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
index a0bfcc90c..8f4f5d3d7 100644
--- a/pkg/domain/infra/abi/cp.go
+++ b/pkg/domain/infra/abi/cp.go
@@ -26,7 +26,7 @@ import (
)
func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) (*entities.ContainerCpReport, error) {
- var extract bool
+ extract := options.Extract
srcCtr, srcPath := parsePath(ic.Libpod, source)
destCtr, destPath := parsePath(ic.Libpod, dest)
@@ -214,7 +214,7 @@ func getPathInfo(path string) (string, os.FileInfo, error) {
}
srcfi, err := os.Stat(path)
if err != nil {
- return "", nil, errors.Wrapf(err, "error reading path %q", path)
+ return "", nil, err
}
return path, srcfi, nil
}
@@ -245,7 +245,7 @@ func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.ID
}
_, err = os.Stat(destdir)
if err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "error checking directory %q", destdir)
+ return err
}
destDirIsExist := err == nil
if err = os.MkdirAll(destdir, 0755); err != nil {
@@ -292,7 +292,7 @@ func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.ID
destfi, err := os.Stat(destPath)
if err != nil {
if !os.IsNotExist(err) || strings.HasSuffix(dest, string(os.PathSeparator)) {
- return errors.Wrapf(err, "failed to get stat of dest path %s", destPath)
+ return err
}
}
if destfi != nil && destfi.IsDir() {
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 25335cf11..ef0e15264 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -39,8 +39,14 @@ const SignatureStoreDir = "/var/lib/containers/sigstore"
func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
_, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
- if err != nil && errors.Cause(err) != define.ErrNoSuchImage {
- return nil, err
+ if err != nil {
+ if errors.Cause(err) == define.ErrMultipleImages {
+ return &entities.BoolReport{Value: true}, nil
+ } else {
+ if errors.Cause(err) != define.ErrNoSuchImage {
+ return nil, err
+ }
+ }
}
return &entities.BoolReport{Value: err == nil}, nil
}
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 3e47dc67a..281b04294 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -5,6 +5,7 @@ import (
libpodImage "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
)
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
@@ -43,12 +44,21 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
VirtualSize: img.VirtualSize,
RepoTags: img.Names(), // may include tags and digests
}
- e.Labels, _ = img.Labels(context.TODO())
+ e.Labels, err = img.Labels(ctx)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
+ }
- ctnrs, _ := img.Containers()
+ ctnrs, err := img.Containers()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error retrieving containers for image %q: you may need to remove the image to resolve the error", img.ID())
+ }
e.Containers = len(ctnrs)
- sz, _ := img.Size(context.TODO())
+ sz, err := img.Size(ctx)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error retrieving size of image %q: you may need to remove the image to resolve the error", img.ID())
+ }
e.Size = int64(*sz)
summaries = append(summaries, &e)
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 6c518e678..ad7128b42 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -25,6 +25,7 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
"github.com/pkg/errors"
)
@@ -90,10 +91,6 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
continue
}
- if !manifest.MIMETypeIsMultiImage(manifestType) {
- appendErr(errors.Errorf("manifest is of type %s (not a list type)", manifestType))
- continue
- }
result = manifestBytes
manType = manifestType
break
@@ -101,7 +98,18 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
if len(result) == 0 && latestErr != nil {
return nil, latestErr
}
- if manType != manifest.DockerV2ListMediaType {
+
+ switch manType {
+ case manifest.DockerV2Schema2MediaType:
+ logrus.Warnf("Warning! The manifest type %s is not a manifest list but a single image.", manType)
+ schema2Manifest, err := manifest.Schema2FromManifest(result)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType)
+ }
+ if result, err = schema2Manifest.Serialize(); err != nil {
+ return nil, err
+ }
+ default:
listBlob, err := manifest.ListFromBlob(result, manType)
if err != nil {
return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType)
@@ -113,10 +121,9 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
if result, err = list.Serialize(); err != nil {
return nil, err
}
-
}
- err = json.Indent(&b, result, "", " ")
- if err != nil {
+
+ if err = json.Indent(&b, result, "", " "); err != nil {
return nil, errors.Wrapf(err, "error rendering manifest %s for display", name)
}
return b.Bytes(), nil
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index f40df828a..4f572fb88 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -43,21 +43,26 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.Net
return reports, nil
}
-func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.NetworkInspectOptions) ([]entities.NetworkInspectReport, error) {
+func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
config, err := ic.Libpod.GetConfig()
if err != nil {
- return nil, err
+ return nil, nil, err
}
-
+ var errs []error
rawCNINetworks := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
rawList, err := network.InspectNetwork(config, name)
if err != nil {
- return nil, err
+ if errors.Cause(err) == define.ErrNoSuchNetwork {
+ errs = append(errs, errors.Errorf("no such network %s", name))
+ continue
+ } else {
+ return nil, nil, errors.Wrapf(err, "error inspecting network %s", name)
+ }
}
rawCNINetworks = append(rawCNINetworks, rawList)
}
- return rawCNINetworks, nil
+ return rawCNINetworks, errs, nil
}
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 348570a20..fbba00984 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -36,8 +36,6 @@ const (
kubeDirectoryPermission = 0755
// https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
kubeFilePermission = 0644
- // Kubernetes sets CPUPeriod to 100000us (100ms): https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
- defaultCPUPeriod = 100000
)
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
@@ -251,7 +249,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
case v1.HostPathDirectoryOrCreate:
if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
if err := os.Mkdir(hostPath.Path, kubeDirectoryPermission); err != nil {
- return nil, errors.Errorf("error creating HostPath %s", volume.Name)
+ return nil, err
}
}
// Label a newly created volume
@@ -262,7 +260,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
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.Errorf("error creating HostPath %s", volume.Name)
+ 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)
@@ -515,10 +513,9 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
return nil, errors.Wrap(err, "Failed to set CPU quota")
}
if milliCPU > 0 {
- containerConfig.Resources.CPUPeriod = defaultCPUPeriod
- // CPU quota is a fraction of the period: milliCPU / 1000.0 * period
- // Or, without floating point math:
- containerConfig.Resources.CPUQuota = milliCPU * defaultCPUPeriod / 1000
+ period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000)
+ containerConfig.Resources.CPUPeriod = period
+ containerConfig.Resources.CPUQuota = quota
}
containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory())
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 57c098166..613c4a6d8 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -123,7 +123,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
}
if err != nil {
- logrus.Error(err)
+ logrus.Error(errors.Wrapf(err, "invalid internal status, try resetting the pause process with %q", os.Args[0]+" system migrate"))
os.Exit(1)
}
if became {
diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
index 0c586cf5c..2aca8f22d 100644
--- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go
+++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
@@ -5,8 +5,10 @@ import (
"syscall"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/signal"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -33,12 +35,16 @@ func ProxySignals(ctr *libpod.Container) {
}
if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil {
+ if errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID())
+ } else {
+ logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err)
+ }
// If the container dies, and we find out here,
// we need to forward that one signal to
// ourselves so that it is not lost, and then
// we terminate the proxy and let the defaults
// play out.
- logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err)
signal.StopCatch(sigBuffer)
if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil {
logrus.Errorf("failed to kill pid %d", syscall.Getpid())
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index 946f258af..a7262f61b 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -4,6 +4,7 @@ import (
"context"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
@@ -71,9 +72,10 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
return reports, nil
}
-func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
+func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]*entities.VolumeInspectReport, []error, error) {
var (
err error
+ errs []error
vols []*libpod.Volume
)
@@ -82,13 +84,18 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
if opts.All {
vols, err = ic.Libpod.GetAllVolumes()
if err != nil {
- return nil, err
+ return nil, nil, err
}
} else {
for _, v := range namesOrIds {
vol, err := ic.Libpod.LookupVolume(v)
if err != nil {
- return nil, errors.Wrapf(err, "error inspecting volume %s", v)
+ if errors.Cause(err) == define.ErrNoSuchVolume {
+ errs = append(errs, errors.Errorf("no such volume %s", v))
+ continue
+ } else {
+ return nil, nil, errors.Wrapf(err, "error inspecting volume %s", v)
+ }
}
vols = append(vols, vol)
}
@@ -98,11 +105,11 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
var uid, gid int
uid, err = v.UID()
if err != nil {
- return nil, err
+ return nil, nil, err
}
gid, err = v.GID()
if err != nil {
- return nil, err
+ return nil, nil, err
}
config := entities.VolumeConfigResponse{
Name: v.Name(),
@@ -117,7 +124,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
}
reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: &config})
}
- return reports, nil
+ return reports, errs, nil
}
func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 7913d79cd..8066e1c00 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -21,6 +21,7 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/specgen"
+ "github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -558,6 +559,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
for _, w := range con.Warnings {
fmt.Fprintf(os.Stderr, "%s\n", w)
}
+ if opts.CIDFile != "" {
+ if err := util.CreateCidFile(opts.CIDFile, con.ID); err != nil {
+ return nil, err
+ }
+ }
report := entities.ContainerRunReport{Id: con.ID}
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index d155fdd9e..15527e02c 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -5,22 +5,34 @@ import (
"github.com/containers/podman/v2/pkg/bindings/network"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
)
func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
return network.List(ic.ClientCxt, options)
}
-func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.NetworkInspectOptions) ([]entities.NetworkInspectReport, error) {
- reports := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
+func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
+ var (
+ reports = make([]entities.NetworkInspectReport, 0, len(namesOrIds))
+ errs = []error{}
+ )
for _, name := range namesOrIds {
report, err := network.Inspect(ic.ClientCxt, name)
if err != nil {
- return nil, err
+ errModel, ok := err.(entities.ErrorModel)
+ if !ok {
+ return nil, nil, err
+ }
+ if errModel.ResponseCode == 404 {
+ errs = append(errs, errors.Errorf("no such network %q", name))
+ continue
+ }
+ return nil, nil, err
}
reports = append(reports, report...)
}
- return reports, nil
+ return reports, errs, nil
}
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index e432d3292..c0df2bb7b 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
)
func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IDOrNameResponse, error) {
@@ -35,25 +36,36 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
return reports, nil
}
-func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
+func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]*entities.VolumeInspectReport, []error, error) {
+ var (
+ reports = make([]*entities.VolumeInspectReport, 0, len(namesOrIds))
+ errs = []error{}
+ )
if opts.All {
vols, err := volumes.List(ic.ClientCxt, nil)
if err != nil {
- return nil, err
+ return nil, nil, err
}
for _, v := range vols {
namesOrIds = append(namesOrIds, v.Name)
}
}
- reports := make([]*entities.VolumeInspectReport, 0, len(namesOrIds))
for _, id := range namesOrIds {
data, err := volumes.Inspect(ic.ClientCxt, id)
if err != nil {
- return nil, err
+ errModel, ok := err.(entities.ErrorModel)
+ if !ok {
+ return nil, nil, err
+ }
+ if errModel.ResponseCode == 404 {
+ errs = append(errs, errors.Errorf("no such volume %q", id))
+ continue
+ }
+ return nil, nil, err
}
reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: data})
}
- return reports, nil
+ return reports, errs, nil
}
func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go
index 38d93b87f..9ebcf8d29 100644
--- a/pkg/spec/parse.go
+++ b/pkg/spec/parse.go
@@ -173,7 +173,7 @@ func ParseDevice(device string) (string, string, string, error) { //nolint
if IsValidDeviceMode(arr[1]) {
permissions = arr[1]
} else {
- if arr[1][0] != '/' {
+ if len(arr[1]) == 0 || arr[1][0] != '/' {
return "", "", "", fmt.Errorf("invalid device mode: %s", arr[1])
}
dst = arr[1]
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index ebf5ec196..b441daf08 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -445,7 +445,7 @@ func getBindMount(args []string) (spec.Mount, error) {
}
setExec = true
newMount.Options = append(newMount.Options, kv[0])
- case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z":
+ 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 {
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index fac02ad01..2d40dba8f 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -52,7 +52,7 @@ func addPrivilegedDevices(g *generate.Generator) error {
if err == unix.EPERM {
continue
}
- return errors.Wrapf(err, "stat %s", d.Path)
+ return err
}
// Skip devices that the user has not access to.
if st.Mode()&0007 == 0 {
@@ -90,7 +90,7 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error {
}
st, err := os.Stat(resolvedDevicePath)
if err != nil {
- return errors.Wrapf(err, "cannot stat device path %s", devicePath)
+ return err
}
if st.IsDir() {
found := false
@@ -231,10 +231,7 @@ func addDevice(g *generate.Generator, device string) error {
}
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)
+ return err
}
perm := "ro"
if strings.Contains(permissions, "w") {
@@ -353,3 +350,8 @@ func deviceFromPath(path string) (*spec.LinuxDevice, error) {
Minor: int64(unix.Minor(devNumber)),
}, nil
}
+
+func supportAmbientCapabilities() bool {
+ err := unix.Prctl(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, 0, 0, 0)
+ return err == nil
+}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index f051537de..53dc35df1 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -223,6 +223,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
for _, overlayVolume := range s.OverlayVolumes {
destinations = append(destinations, overlayVolume.Destination)
}
+ for _, imageVolume := range s.ImageVolumes {
+ destinations = append(destinations, imageVolume.Destination)
+ }
options = append(options, libpod.WithUserVolumes(destinations))
if len(volumes) != 0 {
@@ -248,6 +251,18 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithOverlayVolumes(vols))
}
+ if len(s.ImageVolumes) != 0 {
+ var vols []*libpod.ContainerImageVolume
+ for _, v := range s.ImageVolumes {
+ vols = append(vols, &libpod.ContainerImageVolume{
+ Dest: v.Destination,
+ Source: v.Source,
+ ReadWrite: v.ReadWrite,
+ })
+ }
+ options = append(options, libpod.WithImageVolumes(vols))
+ }
+
if s.Command != nil {
options = append(options, libpod.WithCommand(s.Command))
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 7e4f09dc4..ddc73ca61 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -127,6 +127,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
return nil, errNoInfra
}
toReturn = append(toReturn, libpod.WithIPCNSFrom(infraCtr))
+ toReturn = append(toReturn, libpod.WithShmDir(infraCtr.ShmDir()))
case specgen.FromContainer:
ipcCtr, err := rt.LookupContainer(s.IpcNS.Value)
if err != nil {
@@ -278,7 +279,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
switch s.PidNS.NSMode {
case specgen.Path:
if _, err := os.Stat(s.PidNS.Value); err != nil {
- return errors.Wrapf(err, "cannot find specified PID namespace path %q", s.PidNS.Value)
+ return errors.Wrap(err, "cannot find specified PID namespace path")
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil {
return err
@@ -297,7 +298,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
switch s.IpcNS.NSMode {
case specgen.Path:
if _, err := os.Stat(s.IpcNS.Value); err != nil {
- return errors.Wrapf(err, "cannot find specified IPC namespace path %q", s.IpcNS.Value)
+ return errors.Wrap(err, "cannot find specified IPC namespace path")
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil {
return err
@@ -316,7 +317,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
switch s.UtsNS.NSMode {
case specgen.Path:
if _, err := os.Stat(s.UtsNS.Value); err != nil {
- return errors.Wrapf(err, "cannot find specified UTS namespace path %q", s.UtsNS.Value)
+ return errors.Wrap(err, "cannot find specified UTS namespace path")
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil {
return err
@@ -367,7 +368,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
switch s.UserNS.NSMode {
case specgen.Path:
if _, err := os.Stat(s.UserNS.Value); err != nil {
- return errors.Wrapf(err, "cannot find specified user namespace path %s", s.UserNS.Value)
+ return errors.Wrap(err, "cannot find specified user namespace path")
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), s.UserNS.Value); err != nil {
return err
@@ -410,7 +411,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
switch s.CgroupNS.NSMode {
case specgen.Path:
if _, err := os.Stat(s.CgroupNS.Value); err != nil {
- return errors.Wrapf(err, "cannot find specified cgroup namespace path %s", s.CgroupNS.Value)
+ return errors.Wrap(err, "cannot find specified cgroup namespace path")
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil {
return err
@@ -429,7 +430,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
switch s.NetNS.NSMode {
case specgen.Path:
if _, err := os.Stat(s.NetNS.Value); err != nil {
- return errors.Wrapf(err, "cannot find specified network namespace path %s", s.NetNS.Value)
+ return errors.Wrap(err, "cannot find specified network namespace path")
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
return err
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index d17cd4a9a..dee140282 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -135,7 +135,9 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec.Process.Capabilities.Bounding = caplist
configSpec.Process.Capabilities.Inheritable = caplist
- if s.User == "" || s.User == "root" || s.User == "0" {
+ user := strings.Split(s.User, ":")[0]
+
+ if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" {
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
} else {
@@ -145,6 +147,12 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
}
configSpec.Process.Capabilities.Effective = userCaps
configSpec.Process.Capabilities.Permitted = userCaps
+
+ // Ambient capabilities were added to Linux 4.3. Set ambient
+ // capabilities only when the kernel supports them.
+ if supportAmbientCapabilities() {
+ configSpec.Process.Capabilities.Ambient = userCaps
+ }
}
g.SetProcessNoNewPrivileges(s.NoNewPrivileges)
diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go
index ed337321b..f0ab4b994 100644
--- a/pkg/specgen/generate/validate.go
+++ b/pkg/specgen/generate/validate.go
@@ -1,22 +1,20 @@
package generate
import (
+ "os"
+ "path/filepath"
+
"github.com/containers/common/pkg/sysinfo"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/specgen"
+ "github.com/containers/podman/v2/utils"
"github.com/pkg/errors"
)
-// Verify resource limits are sanely set, removing any limits that are not
-// possible with the current cgroups config.
-func verifyContainerResources(s *specgen.SpecGenerator) ([]string, error) {
+// Verify resource limits are sanely set when running on cgroup v1.
+func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error) {
warnings := []string{}
- cgroup2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil || cgroup2 {
- return warnings, err
- }
-
sysInfo := sysinfo.New(true)
if s.ResourceLimits == nil {
@@ -24,9 +22,7 @@ func verifyContainerResources(s *specgen.SpecGenerator) ([]string, error) {
}
if s.ResourceLimits.Unified != nil {
- if !cgroup2 {
- return nil, errors.New("Cannot use --cgroup-conf without cgroup v2")
- }
+ return nil, errors.New("Cannot use --cgroup-conf without cgroup v2")
}
// Memory checks
@@ -38,7 +34,7 @@ func verifyContainerResources(s *specgen.SpecGenerator) ([]string, error) {
memory.Swap = nil
}
if memory.Limit != nil && memory.Swap != nil && !sysInfo.SwapLimit {
- warnings = append(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
+ warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.")
memory.Swap = nil
}
if memory.Limit != nil && memory.Swap != nil && *memory.Swap < *memory.Limit {
@@ -163,3 +159,48 @@ func verifyContainerResources(s *specgen.SpecGenerator) ([]string, error) {
return warnings, nil
}
+
+// Verify resource limits are sanely set when running on cgroup v2.
+func verifyContainerResourcesCgroupV2(s *specgen.SpecGenerator) ([]string, error) {
+ warnings := []string{}
+
+ if s.ResourceLimits == nil {
+ return warnings, nil
+ }
+
+ if s.ResourceLimits.Memory != nil && s.ResourceLimits.Memory.Swap != nil {
+ own, err := utils.GetOwnCgroup()
+ if err != nil {
+ return warnings, err
+ }
+ memoryMax := filepath.Join("/sys/fs/cgroup", own, "memory.max")
+ memorySwapMax := filepath.Join("/sys/fs/cgroup", own, "memory.swap.max")
+ _, errMemoryMax := os.Stat(memoryMax)
+ _, errMemorySwapMax := os.Stat(memorySwapMax)
+ // Differently than cgroup v1, the memory.*max files are not present in the
+ // root directory, so we cannot query directly that, so as best effort use
+ // the current cgroup.
+ // Check whether memory.max exists in the current cgroup and memory.swap.max
+ // does not. In this case we can be sure memory swap is not enabled.
+ // If both files don't exist, the memory controller might not be enabled
+ // for the current cgroup.
+ if errMemoryMax == nil && errMemorySwapMax != nil {
+ warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.")
+ s.ResourceLimits.Memory.Swap = nil
+ }
+ }
+ return warnings, nil
+}
+
+// Verify resource limits are sanely set, removing any limits that are not
+// possible with the current cgroups config.
+func verifyContainerResources(s *specgen.SpecGenerator) ([]string, error) {
+ cgroup2, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return []string{}, err
+ }
+ if cgroup2 {
+ return verifyContainerResourcesCgroupV2(s)
+ }
+ return verifyContainerResourcesCgroupV1(s)
+}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index fa4af7b2b..d68f55402 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -214,6 +214,9 @@ type ContainerStorageConfig struct {
// Overlay volumes are named volumes that will be added to the container.
// Optional.
OverlayVolumes []*OverlayVolume `json:"overlay_volumes,omitempty"`
+ // Image volumes bind-mount a container-image mount into the container.
+ // Optional.
+ ImageVolumes []*ImageVolume `json:"image_volumes,omitempty"`
// Devices are devices that will be added to the container.
// Optional.
Devices []spec.LinuxDevice `json:"devices,omitempty"`
@@ -476,6 +479,19 @@ type OverlayVolume struct {
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/terminal/util.go b/pkg/terminal/util.go
index ab3dc54e4..169bec2af 100644
--- a/pkg/terminal/util.go
+++ b/pkg/terminal/util.go
@@ -12,6 +12,7 @@ import (
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/knownhosts"
"golang.org/x/crypto/ssh/terminal"
"k8s.io/client-go/util/homedir"
)
@@ -114,6 +115,9 @@ func HostKey(host string) ssh.PublicKey {
return nil
}
+ // support -H parameter for ssh-keyscan
+ hashhost := knownhosts.HashHostname(host)
+
scanner := bufio.NewScanner(fd)
for scanner.Scan() {
_, hosts, key, _, _, err := ssh.ParseKnownHosts(scanner.Bytes())
@@ -123,7 +127,7 @@ func HostKey(host string) ssh.PublicKey {
}
for _, h := range hosts {
- if h == host {
+ if h == host || h == hashhost {
return key
}
}
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index eab2657e3..580aaf4f2 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -57,7 +57,7 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'rw' and 'ro' can be used")
}
foundWrite = true
- case "private", "rprivate", "slave", "rslave", "shared", "rshared":
+ case "private", "rprivate", "slave", "rslave", "shared", "rshared", "unbindable", "runbindable":
if foundProp {
return nil, errors.Wrapf(ErrDupeMntOption, "only one root propagation mode can be used")
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 91aba9fa7..415fd169b 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -638,3 +638,41 @@ func ValidateSysctls(strSlice []string) (map[string]string, error) {
func DefaultContainerConfig() *config.Config {
return containerConfig
}
+
+func CreateCidFile(cidfile string, id string) error {
+ cidFile, err := OpenExclusiveFile(cidfile)
+ if err != nil {
+ if os.IsExist(err) {
+ return errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", cidfile)
+ }
+ return errors.Errorf("error opening cidfile %s", cidfile)
+ }
+ if _, err = cidFile.WriteString(id); err != nil {
+ logrus.Error(err)
+ }
+ cidFile.Close()
+ return nil
+}
+
+// DefaultCPUPeriod is the default CPU period is 100us, which is the same default
+// as Kubernetes.
+const DefaultCPUPeriod uint64 = 100000
+
+// CoresToPeriodAndQuota converts a fraction of cores to the equivalent
+// Completely Fair Scheduler (CFS) parameters period and quota.
+//
+// Cores is a fraction of the CFS period that a container may use. Period and
+// Quota are in microseconds.
+func CoresToPeriodAndQuota(cores float64) (uint64, int64) {
+ return DefaultCPUPeriod, int64(cores * float64(DefaultCPUPeriod))
+}
+
+// PeriodAndQuotaToCores takes the CFS parameters period and quota and returns
+// a fraction that represents the limit to the number of cores that can be
+// utilized over the scheduling period.
+//
+// Cores is a fraction of the CFS period that a container may use. Period and
+// Quota are in microseconds.
+func PeriodAndQuotaToCores(period uint64, quota int64) float64 {
+ return float64(quota) / float64(period)
+}
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index a9b37844e..cb737bd76 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -257,3 +257,23 @@ func TestValidateSysctlBadSysctl(t *testing.T) {
_, err := ValidateSysctls(strSlice)
assert.Error(t, err)
}
+
+func TestCoresToPeriodAndQuota(t *testing.T) {
+ cores := 1.0
+ expectedPeriod := DefaultCPUPeriod
+ expectedQuota := int64(DefaultCPUPeriod)
+
+ actualPeriod, actualQuota := CoresToPeriodAndQuota(cores)
+ assert.Equal(t, actualPeriod, expectedPeriod, "Period does not match")
+ assert.Equal(t, actualQuota, expectedQuota, "Quota does not match")
+}
+
+func TestPeriodAndQuotaToCores(t *testing.T) {
+ var (
+ period uint64 = 100000
+ quota int64 = 50000
+ expectedCores = 0.5
+ )
+
+ assert.Equal(t, PeriodAndQuotaToCores(period, quota), expectedCores)
+}