summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/annotations/annotations.go76
-rw-r--r--pkg/api/handlers/compat/containers_stats.go2
-rw-r--r--pkg/api/handlers/compat/images_prune.go2
-rw-r--r--pkg/api/handlers/compat/networks.go2
-rw-r--r--pkg/api/handlers/libpod/images.go25
-rw-r--r--pkg/api/handlers/libpod/manifests.go46
-rw-r--r--pkg/api/handlers/libpod/play.go53
-rw-r--r--pkg/api/handlers/utils/images.go2
-rw-r--r--pkg/api/server/register_exec.go2
-rw-r--r--pkg/api/server/register_images.go4
-rw-r--r--pkg/api/server/register_networks.go11
-rw-r--r--pkg/api/server/swagger.go9
-rw-r--r--pkg/bindings/containers/attach.go6
-rw-r--r--pkg/bindings/containers/logs.go2
-rw-r--r--pkg/bindings/errors.go2
-rw-r--r--pkg/bindings/images/build.go47
-rw-r--r--pkg/bindings/images/types.go8
-rw-r--r--pkg/bindings/images/types_import_options.go45
-rw-r--r--pkg/bindings/images/types_remove_options.go15
-rw-r--r--pkg/bindings/manifests/manifests.go138
-rw-r--r--pkg/bindings/manifests/types.go45
-rw-r--r--pkg/bindings/manifests/types_add_options.go60
-rw-r--r--pkg/bindings/manifests/types_modify_options.go60
-rw-r--r--pkg/bindings/play/play.go39
-rw-r--r--pkg/bindings/test/attach_test.go3
-rw-r--r--pkg/bindings/test/auth_test.go3
-rw-r--r--pkg/bindings/test/common_test.go2
-rw-r--r--pkg/bindings/test/containers_test.go3
-rw-r--r--pkg/checkpoint/crutils/checkpoint_restore_utils.go9
-rw-r--r--pkg/domain/entities/engine_container.go4
-rw-r--r--pkg/domain/entities/images.go3
-rw-r--r--pkg/domain/entities/types.go4
-rw-r--r--pkg/domain/filters/containers.go6
-rw-r--r--pkg/domain/filters/pods.go6
-rw-r--r--pkg/domain/infra/abi/containers.go36
-rw-r--r--pkg/domain/infra/abi/images.go15
-rw-r--r--pkg/domain/infra/abi/images_test.go2
-rw-r--r--pkg/domain/infra/abi/play.go32
-rw-r--r--pkg/domain/infra/abi/system.go22
-rw-r--r--pkg/domain/infra/abi/terminal/sigproxy_linux.go2
-rw-r--r--pkg/domain/infra/abi/terminal/terminal_linux.go2
-rw-r--r--pkg/domain/infra/abi/volumes.go3
-rw-r--r--pkg/domain/infra/tunnel/containers.go6
-rw-r--r--pkg/domain/infra/tunnel/events.go2
-rw-r--r--pkg/domain/infra/tunnel/images.go3
-rw-r--r--pkg/domain/infra/tunnel/manifest.go8
-rw-r--r--pkg/domain/infra/tunnel/play.go9
-rw-r--r--pkg/env/env.go2
-rw-r--r--pkg/errorhandling/errorhandling.go2
-rw-r--r--pkg/inspect/inspect.go6
-rw-r--r--pkg/k8s.io/api/core/v1/types.go2
-rw-r--r--pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go6
-rw-r--r--pkg/lookup/lookup.go2
-rw-r--r--pkg/machine/config.go9
-rw-r--r--pkg/machine/config_test.go71
-rw-r--r--pkg/machine/fedora.go5
-rw-r--r--pkg/machine/ignition.go5
-rw-r--r--pkg/machine/pull.go2
-rw-r--r--pkg/machine/qemu/config.go124
-rw-r--r--pkg/machine/qemu/config_test.go103
-rw-r--r--pkg/machine/qemu/machine.go81
-rw-r--r--pkg/machine/wsl/machine.go7
-rw-r--r--pkg/namespaces/namespaces.go2
-rw-r--r--pkg/rootless/rootless.go14
-rw-r--r--pkg/rootless/rootless_linux.go12
-rw-r--r--pkg/signal/signal_common.go2
-rw-r--r--pkg/specgen/container_validate.go6
-rw-r--r--pkg/specgen/generate/config_linux.go9
-rw-r--r--pkg/specgen/generate/container.go6
-rw-r--r--pkg/specgen/generate/kube/volume.go2
-rw-r--r--pkg/specgen/generate/namespaces.go2
-rw-r--r--pkg/specgen/generate/ports_bench_test.go2
-rw-r--r--pkg/specgen/generate/security.go7
-rw-r--r--pkg/specgen/generate/storage.go2
-rw-r--r--pkg/specgen/namespaces.go37
-rw-r--r--pkg/specgenutil/specgen.go5
-rw-r--r--pkg/systemd/dbus.go1
-rw-r--r--pkg/systemd/generate/containers.go4
-rw-r--r--pkg/systemd/generate/pods.go8
-rw-r--r--pkg/terminal/console_unix.go2
-rw-r--r--pkg/util/camelcase/camelcase.go4
-rw-r--r--pkg/util/utils.go22
-rw-r--r--pkg/util/utils_linux.go9
83 files changed, 1104 insertions, 367 deletions
diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go
index 8badab20d..a22222f10 100644
--- a/pkg/annotations/annotations.go
+++ b/pkg/annotations/annotations.go
@@ -1,122 +1,122 @@
package annotations
const (
- // Annotations carries the received Kubelet annotations
+ // Annotations carries the received Kubelet annotations.
Annotations = "io.kubernetes.cri-o.Annotations"
- // ContainerID is the container ID annotation
+ // ContainerID is the container ID annotation.
ContainerID = "io.kubernetes.cri-o.ContainerID"
- // ContainerName is the container name annotation
+ // ContainerName is the container name annotation.
ContainerName = "io.kubernetes.cri-o.ContainerName"
- // ContainerType is the container type (sandbox or container) annotation
+ // ContainerType is the container type (sandbox or container) annotation.
ContainerType = "io.kubernetes.cri-o.ContainerType"
- // Created is the container creation time annotation
+ // Created is the container creation time annotation.
Created = "io.kubernetes.cri-o.Created"
- // HostName is the container host name annotation
+ // HostName is the container host name annotation.
HostName = "io.kubernetes.cri-o.HostName"
- // CgroupParent is the sandbox cgroup parent
+ // CgroupParent is the sandbox cgroup parent.
CgroupParent = "io.kubernetes.cri-o.CgroupParent"
- // IP is the container ipv4 or ipv6 address
+ // IP is the container ipv4 or ipv6 address.
IP = "io.kubernetes.cri-o.IP"
- // NamespaceOptions store the options for namespaces
+ // NamespaceOptions store the options for namespaces.
NamespaceOptions = "io.kubernetes.cri-o.NamespaceOptions"
- // SeccompProfilePath is the node seccomp profile path
+ // SeccompProfilePath is the node seccomp profile path.
SeccompProfilePath = "io.kubernetes.cri-o.SeccompProfilePath"
- // Image is the container image ID annotation
+ // Image is the container image ID annotation.
Image = "io.kubernetes.cri-o.Image"
- // ImageName is the container image name annotation
+ // ImageName is the container image name annotation.
ImageName = "io.kubernetes.cri-o.ImageName"
- // ImageRef is the container image ref annotation
+ // ImageRef is the container image ref annotation.
ImageRef = "io.kubernetes.cri-o.ImageRef"
- // KubeName is the kubernetes name annotation
+ // KubeName is the kubernetes name annotation.
KubeName = "io.kubernetes.cri-o.KubeName"
- // PortMappings holds the port mappings for the sandbox
+ // PortMappings holds the port mappings for the sandbox.
PortMappings = "io.kubernetes.cri-o.PortMappings"
- // Labels are the kubernetes labels annotation
+ // Labels are the kubernetes labels annotation.
Labels = "io.kubernetes.cri-o.Labels"
- // LogPath is the container logging path annotation
+ // LogPath is the container logging path annotation.
LogPath = "io.kubernetes.cri-o.LogPath"
- // Metadata is the container metadata annotation
+ // Metadata is the container metadata annotation.
Metadata = "io.kubernetes.cri-o.Metadata"
- // Name is the pod name annotation
+ // Name is the pod name annotation.
Name = "io.kubernetes.cri-o.Name"
- // Namespace is the pod namespace annotation
+ // Namespace is the pod namespace annotation.
Namespace = "io.kubernetes.cri-o.Namespace"
- // PrivilegedRuntime is the annotation for the privileged runtime path
+ // PrivilegedRuntime is the annotation for the privileged runtime path.
PrivilegedRuntime = "io.kubernetes.cri-o.PrivilegedRuntime"
- // ResolvPath is the resolver configuration path annotation
+ // ResolvPath is the resolver configuration path annotation.
ResolvPath = "io.kubernetes.cri-o.ResolvPath"
- // HostnamePath is the path to /etc/hostname to bind mount annotation
+ // HostnamePath is the path to /etc/hostname to bind mount annotation.
HostnamePath = "io.kubernetes.cri-o.HostnamePath"
- // SandboxID is the sandbox ID annotation
+ // SandboxID is the sandbox ID annotation.
SandboxID = "io.kubernetes.cri-o.SandboxID"
- // SandboxName is the sandbox name annotation
+ // SandboxName is the sandbox name annotation.
SandboxName = "io.kubernetes.cri-o.SandboxName"
- // ShmPath is the shared memory path annotation
+ // ShmPath is the shared memory path annotation.
ShmPath = "io.kubernetes.cri-o.ShmPath"
- // MountPoint is the mount point of the container rootfs
+ // MountPoint is the mount point of the container rootfs.
MountPoint = "io.kubernetes.cri-o.MountPoint"
- // RuntimeHandler is the annotation for runtime handler
+ // RuntimeHandler is the annotation for runtime handler.
RuntimeHandler = "io.kubernetes.cri-o.RuntimeHandler"
- // TTY is the terminal path annotation
+ // TTY is the terminal path annotation.
TTY = "io.kubernetes.cri-o.TTY"
- // Stdin is the stdin annotation
+ // Stdin is the stdin annotation.
Stdin = "io.kubernetes.cri-o.Stdin"
- // StdinOnce is the stdin_once annotation
+ // StdinOnce is the stdin_once annotation.
StdinOnce = "io.kubernetes.cri-o.StdinOnce"
- // Volumes is the volumes annotation
+ // Volumes is the volumes annotation.
Volumes = "io.kubernetes.cri-o.Volumes"
- // HostNetwork indicates whether the host network namespace is used or not
+ // HostNetwork indicates whether the host network namespace is used or not.
HostNetwork = "io.kubernetes.cri-o.HostNetwork"
- // CNIResult is the JSON string representation of the Result from CNI
+ // CNIResult is the JSON string representation of the Result from CNI.
CNIResult = "io.kubernetes.cri-o.CNIResult"
// ContainerManager is the annotation key for indicating the creator and
- // manager of the container
+ // manager of the container.
ContainerManager = "io.container.manager"
)
// ContainerType values
const (
- // ContainerTypeSandbox represents a pod sandbox container
+ // ContainerTypeSandbox represents a pod sandbox container.
ContainerTypeSandbox = "sandbox"
- // ContainerTypeContainer represents a container running within a pod
+ // ContainerTypeContainer represents a container running within a pod.
ContainerTypeContainer = "container"
)
// ContainerManagerLibpod indicates that libpod created and manages the
-// container
+// container.
const ContainerManagerLibpod = "libpod"
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go
index 99f14d02f..77b16b03e 100644
--- a/pkg/api/handlers/compat/containers_stats.go
+++ b/pkg/api/handlers/compat/containers_stats.go
@@ -56,7 +56,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
return
}
- stats, err := ctnr.GetContainerStats(&define.ContainerStats{})
+ stats, err := ctnr.GetContainerStats(nil)
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "failed to obtain Container %s stats", name))
return
diff --git a/pkg/api/handlers/compat/images_prune.go b/pkg/api/handlers/compat/images_prune.go
index 88776dc49..c0be9da7d 100644
--- a/pkg/api/handlers/compat/images_prune.go
+++ b/pkg/api/handlers/compat/images_prune.go
@@ -43,7 +43,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
return
}
- idr := make([]types.ImageDeleteResponseItem, len(imagePruneReports))
+ idr := make([]types.ImageDeleteResponseItem, 0, len(imagePruneReports))
var reclaimedSpace uint64
var errorMsg bytes.Buffer
for _, p := range imagePruneReports {
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index eb1a5d59c..89d914e0a 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -242,7 +242,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
body := struct {
ID string `json:"Id"`
- Warning []string
+ Warning string
}{
ID: newNetwork.ID,
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index eb9fb12a6..cddf4c205 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -367,10 +367,13 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
query := struct {
- Changes []string `schema:"changes"`
- Message string `schema:"message"`
- Reference string `schema:"reference"`
- URL string `schema:"URL"`
+ Changes []string `schema:"changes"`
+ Message string `schema:"message"`
+ Reference string `schema:"reference"`
+ URL string `schema:"URL"`
+ OS string `schema:"OS"`
+ Architecture string `schema:"Architecture"`
+ Variant string `schema:"Variant"`
}{
// Add defaults here once needed.
}
@@ -402,10 +405,13 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
imageEngine := abi.ImageEngine{Libpod: runtime}
importOptions := entities.ImageImportOptions{
- Changes: query.Changes,
- Message: query.Message,
- Reference: query.Reference,
- Source: source,
+ Changes: query.Changes,
+ Message: query.Message,
+ Reference: query.Reference,
+ OS: query.OS,
+ Architecture: query.Architecture,
+ Variant: query.Variant,
+ Source: source,
}
report, err := imageEngine.Import(r.Context(), importOptions)
if err != nil {
@@ -613,6 +619,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
query := struct {
All bool `schema:"all"`
Force bool `schema:"force"`
+ Ignore bool `schema:"ignore"`
Images []string `schema:"images"`
}{}
@@ -621,7 +628,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
return
}
- opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force}
+ opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force, Ignore: query.Ignore}
imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
strErrs := errorhandling.ErrorsToStrings(rmErrors)
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index 250736579..b823a56b6 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -162,13 +162,35 @@ func ManifestAdd(w http.ResponseWriter, r *http.Request) {
// Wrapper to support 3.x with 4.x libpod
query := struct {
entities.ManifestAddOptions
- Images []string
+ Images []string
+ TLSVerify bool `schema:"tlsVerify"`
}{}
if err := json.NewDecoder(r.Body).Decode(&query); err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
+ authconf, authfile, err := auth.GetCredentials(r)
+ if err != nil {
+ utils.Error(w, http.StatusBadRequest, err)
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+ var username, password string
+ if authconf != nil {
+ username = authconf.Username
+ password = authconf.Password
+ }
+ query.ManifestAddOptions.Authfile = authfile
+ query.ManifestAddOptions.Username = username
+ query.ManifestAddOptions.Password = password
+ if sys := runtime.SystemContext(); sys != nil {
+ query.ManifestAddOptions.CertDir = sys.DockerCertPath
+ }
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ query.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
name := utils.GetName(r)
if _, err := runtime.LibimageRuntime().LookupManifestList(name); err != nil {
utils.Error(w, http.StatusNotFound, err)
@@ -271,7 +293,7 @@ func ManifestPushV3(w http.ResponseWriter, r *http.Request) {
utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "error pushing image %q", query.Destination))
return
}
- utils.WriteResponse(w, http.StatusOK, digest)
+ utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: digest})
}
// ManifestPush push image to registry
@@ -350,6 +372,24 @@ func ManifestModify(w http.ResponseWriter, r *http.Request) {
return
}
+ authconf, authfile, err := auth.GetCredentials(r)
+ if err != nil {
+ utils.Error(w, http.StatusBadRequest, err)
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+ var username, password string
+ if authconf != nil {
+ username = authconf.Username
+ password = authconf.Password
+ }
+ body.ManifestAddOptions.Authfile = authfile
+ body.ManifestAddOptions.Username = username
+ body.ManifestAddOptions.Password = password
+ if sys := runtime.SystemContext(); sys != nil {
+ body.ManifestAddOptions.CertDir = sys.DockerCertPath
+ }
+
var report entities.ManifestModifyReport
switch {
case strings.EqualFold("update", body.Operation):
@@ -401,7 +441,7 @@ func ManifestModify(w http.ResponseWriter, r *http.Request) {
case len(report.Errors) > 0 && len(report.Images) > 0:
statusCode = http.StatusConflict
case len(report.Errors) > 0:
- statusCode = http.StatusInternalServerError
+ statusCode = http.StatusBadRequest
}
utils.WriteResponse(w, statusCode, report)
}
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index aed889298..ca9ada761 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -1,11 +1,8 @@
package libpod
import (
- "io"
- "io/ioutil"
"net"
"net/http"
- "os"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/libpod"
@@ -16,7 +13,6 @@ import (
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func PlayKube(w http.ResponseWriter, r *http.Request) {
@@ -62,28 +58,6 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
staticMACs = append(staticMACs, mac)
}
- // Fetch the K8s YAML file from the body, and copy it to a temp file.
- tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
- if err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- defer func() {
- if err := os.Remove(tmpfile.Name()); err != nil {
- logrus.Warn(err)
- }
- }()
- if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
- if err := tmpfile.Close(); err != nil {
- logrus.Warn(err)
- }
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
- return
- }
authConf, authfile, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, http.StatusBadRequest, err)
@@ -116,7 +90,8 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
if _, found := r.URL.Query()["start"]; found {
options.Start = types.NewOptionalBool(query.Start)
}
- report, err := containerEngine.PlayKube(r.Context(), tmpfile.Name(), options)
+ report, err := containerEngine.PlayKube(r.Context(), r.Body, options)
+ _ = r.Body.Close()
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file"))
return
@@ -126,30 +101,10 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
func PlayKubeDown(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
- tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
- if err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- defer func() {
- if err := os.Remove(tmpfile.Name()); err != nil {
- logrus.Warn(err)
- }
- }()
- if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
- if err := tmpfile.Close(); err != nil {
- logrus.Warn(err)
- }
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
- return
- }
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := new(entities.PlayKubeDownOptions)
- report, err := containerEngine.PlayKubeDown(r.Context(), tmpfile.Name(), *options)
+ report, err := containerEngine.PlayKubeDown(r.Context(), r.Body, *options)
+ _ = r.Body.Close()
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error tearing down YAML file"))
return
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index 15b16bc43..7154f5616 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -63,7 +63,7 @@ func IsRegistryReference(name string) error {
imageRef, err := alltransports.ParseImageName(name)
if err != nil {
// No supported transport -> assume a docker-stype reference.
- return nil
+ return nil // nolint: nilerr
}
if imageRef.Transport().Name() == docker.Transport.Name() {
return nil
diff --git a/pkg/api/server/register_exec.go b/pkg/api/server/register_exec.go
index c19ca7859..90136463d 100644
--- a/pkg/api/server/register_exec.go
+++ b/pkg/api/server/register_exec.go
@@ -169,7 +169,7 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// - application/json
// responses:
// 200:
- // description: no error
+ // $ref: "#/responses/InspectExecSession"
// 404:
// $ref: "#/responses/NoSuchExecInstance"
// 500:
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 017310f12..89f808e7d 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -944,6 +944,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// name: force
// description: Force image removal (including containers using the images).
// type: boolean
+ // - in: query
+ // name: ignore
+ // description: Ignore if a specified image does not exist and do not throw an error.
+ // type: boolean
// produces:
// - application/json
// responses:
diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go
index 4466c938f..b900aa953 100644
--- a/pkg/api/server/register_networks.go
+++ b/pkg/api/server/register_networks.go
@@ -105,8 +105,15 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
// schema:
// $ref: "#/definitions/NetworkCreateRequest"
// responses:
- // 200:
- // $ref: "#/responses/CompatNetworkCreate"
+ // 201:
+ // description: network created
+ // schema:
+ // type: object
+ // properties:
+ // Id:
+ // type: string
+ // Warning:
+ // type: string
// 400:
// $ref: "#/responses/BadParamError"
// 500:
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index 9b652be87..6cf89581a 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -235,3 +235,12 @@ type swagSystemAuthResponse struct {
entities.AuthReport
}
}
+
+// Inspect response
+// swagger:response InspectExecSession
+type swagInspectExecSession struct {
+ // in:body
+ Body struct {
+ define.InspectExecSession
+ }
+}
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index f410606e4..80702ea98 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -242,7 +242,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
}
}
case fd == 3:
- return fmt.Errorf("error from service from stream: %s", frame)
+ return fmt.Errorf("from service from stream: %s", frame)
default:
return fmt.Errorf("unrecognized channel '%d' in header, 0-3 supported", fd)
}
@@ -279,7 +279,7 @@ func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error
n, err := io.ReadFull(r, buffer[0:length])
if err != nil {
- return nil, nil
+ return nil, err
}
if n < length {
err = io.ErrUnexpectedEOF
@@ -562,7 +562,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
}
}
case fd == 3:
- return fmt.Errorf("error from service from stream: %s", frame)
+ return fmt.Errorf("from service from stream: %s", frame)
default:
return fmt.Errorf("unrecognized channel '%d' in header, 0-3 supported", fd)
}
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
index 7f7f07395..8ea8ed7fa 100644
--- a/pkg/bindings/containers/logs.go
+++ b/pkg/bindings/containers/logs.go
@@ -57,7 +57,7 @@ func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan,
case 2:
stderrChan <- string(frame)
case 3:
- return errors.New("error from service in stream: " + string(frame))
+ return errors.New("from service in stream: " + string(frame))
default:
return fmt.Errorf("unrecognized input header: %d", fd)
}
diff --git a/pkg/bindings/errors.go b/pkg/bindings/errors.go
index 44973eb41..eb95764ba 100644
--- a/pkg/bindings/errors.go
+++ b/pkg/bindings/errors.go
@@ -54,6 +54,6 @@ func CheckResponseCode(inError error) (int, error) {
case *errorhandling.PodConflictErrorModel:
return e.Code(), nil
default:
- return -1, errors.New("error is not type ErrorModel")
+ return -1, errors.New("is not type ErrorModel")
}
}
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index c508cb767..f6739b7ca 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"net/http"
"net/url"
@@ -241,7 +242,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
params.Add("platform", platform)
}
}
- if contextDir, err := filepath.EvalSymlinks(options.ContextDirectory); err == nil {
+ var err error
+ var contextDir string
+ if contextDir, err = filepath.EvalSymlinks(options.ContextDirectory); err == nil {
options.ContextDirectory = contextDir
}
@@ -301,7 +304,6 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
var (
headers http.Header
- err error
)
if options.SystemContext != nil && options.SystemContext.DockerAuthConfig != nil {
headers, err = auth.MakeXRegistryAuthHeader(options.SystemContext, options.SystemContext.DockerAuthConfig.Username, options.SystemContext.DockerAuthConfig.Password)
@@ -325,7 +327,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
}
}
- contextDir, err := filepath.Abs(options.ContextDirectory)
+ contextDir, err = filepath.Abs(options.ContextDirectory)
if err != nil {
logrus.Errorf("Cannot find absolute path of %v: %v", options.ContextDirectory, err)
return nil, err
@@ -556,16 +558,27 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
merr = multierror.Append(merr, err)
return
}
-
- err = filepath.Walk(s, func(path string, info os.FileInfo, err error) error {
+ err = filepath.WalkDir(s, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
- if path == s {
- return nil // skip root dir
+ // check if what we are given is an empty dir, if so then continue w/ it. Else return.
+ // if we are given a file or a symlink, we do not want to exclude it.
+ if d.IsDir() && s == path {
+ var p *os.File
+ p, err = os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer p.Close()
+ _, err = p.Readdir(1)
+ if err != io.EOF {
+ return nil // non empty root dir, need to return
+ } else if err != nil {
+ logrus.Errorf("While reading directory %v: %v", path, err)
+ }
}
-
name := filepath.ToSlash(strings.TrimPrefix(path, s+string(filepath.Separator)))
excluded, err := pm.Matches(name) // nolint:staticcheck
@@ -576,7 +589,11 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
return nil
}
- if info.Mode().IsRegular() { // add file item
+ if d.Type().IsRegular() { // add file item
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
di, isHardLink := checkHardLink(info)
if err != nil {
return err
@@ -612,7 +629,11 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
seen[di] = name
}
return err
- } else if info.Mode().IsDir() { // add folders
+ } else if d.IsDir() { // add folders
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
hdr, lerr := tar.FileInfoHeader(info, name)
if lerr != nil {
return lerr
@@ -622,11 +643,15 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
if lerr := tw.WriteHeader(hdr); lerr != nil {
return lerr
}
- } else if info.Mode()&os.ModeSymlink != 0 { // add symlinks as it, not content
+ } else if d.Type()&os.ModeSymlink != 0 { // add symlinks as it, not content
link, err := os.Readlink(path)
if err != nil {
return err
}
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
hdr, lerr := tar.FileInfoHeader(info, link)
if lerr != nil {
return lerr
diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go
index a44a3527f..75cb38a0a 100644
--- a/pkg/bindings/images/types.go
+++ b/pkg/bindings/images/types.go
@@ -11,6 +11,8 @@ type RemoveOptions struct {
All *bool
// Forces removes all containers based on the image
Force *bool
+ // Ignore if a specified image does not exist and do not throw an error.
+ Ignore *bool
}
//go:generate go run ../generator/generator.go DiffOptions
@@ -101,6 +103,12 @@ type ImportOptions struct {
Reference *string
// Url to option image to import. Cannot be used with the reader
URL *string
+ // OS for the imported image
+ OS *string
+ // Architecture for the imported image
+ Architecture *string
+ // Variant for the imported image
+ Variant *string
}
//go:generate go run ../generator/generator.go PushOptions
diff --git a/pkg/bindings/images/types_import_options.go b/pkg/bindings/images/types_import_options.go
index ea66fa312..f958fe8b4 100644
--- a/pkg/bindings/images/types_import_options.go
+++ b/pkg/bindings/images/types_import_options.go
@@ -76,3 +76,48 @@ func (o *ImportOptions) GetURL() string {
}
return *o.URL
}
+
+// WithOS set field OS to given value
+func (o *ImportOptions) WithOS(value string) *ImportOptions {
+ o.OS = &value
+ return o
+}
+
+// GetOS returns value of field OS
+func (o *ImportOptions) GetOS() string {
+ if o.OS == nil {
+ var z string
+ return z
+ }
+ return *o.OS
+}
+
+// WithArchitecture set field Architecture to given value
+func (o *ImportOptions) WithArchitecture(value string) *ImportOptions {
+ o.Architecture = &value
+ return o
+}
+
+// GetArchitecture returns value of field Architecture
+func (o *ImportOptions) GetArchitecture() string {
+ if o.Architecture == nil {
+ var z string
+ return z
+ }
+ return *o.Architecture
+}
+
+// WithVariant set field Variant to given value
+func (o *ImportOptions) WithVariant(value string) *ImportOptions {
+ o.Variant = &value
+ return o
+}
+
+// GetVariant returns value of field Variant
+func (o *ImportOptions) GetVariant() string {
+ if o.Variant == nil {
+ var z string
+ return z
+ }
+ return *o.Variant
+}
diff --git a/pkg/bindings/images/types_remove_options.go b/pkg/bindings/images/types_remove_options.go
index 1fbe5f4ea..613a33183 100644
--- a/pkg/bindings/images/types_remove_options.go
+++ b/pkg/bindings/images/types_remove_options.go
@@ -46,3 +46,18 @@ func (o *RemoveOptions) GetForce() bool {
}
return *o.Force
}
+
+// WithIgnore set field Ignore to given value
+func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
+ o.Ignore = &value
+ return o
+}
+
+// GetIgnore returns value of field Ignore
+func (o *RemoveOptions) GetIgnore() bool {
+ if o.Ignore == nil {
+ var z bool
+ return z
+ }
+ return *o.Ignore
+}
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index 458cb913a..70b3819f5 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -2,20 +2,24 @@ package manifests
import (
"context"
- "errors"
"fmt"
+ "io/ioutil"
"net/http"
- "net/url"
"strconv"
"strings"
"github.com/blang/semver"
"github.com/containers/image/v5/manifest"
+ imageTypes "github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/api/handlers"
+ "github.com/containers/podman/v4/pkg/auth"
"github.com/containers/podman/v4/pkg/bindings"
"github.com/containers/podman/v4/pkg/bindings/images"
+ "github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/version"
jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
)
// Create creates a manifest for the given name. Optional images to be associated with
@@ -93,15 +97,19 @@ func Add(ctx context.Context, name string, options *AddOptions) (string, error)
if bindings.ServiceVersion(ctx).GTE(semver.MustParse("4.0.0")) {
optionsv4 := ModifyOptions{
- All: options.All,
- Annotations: options.Annotation,
- Arch: options.Arch,
- Features: options.Features,
- Images: options.Images,
- OS: options.OS,
- OSFeatures: nil,
- OSVersion: options.OSVersion,
- Variant: options.Variant,
+ All: options.All,
+ Annotations: options.Annotation,
+ Arch: options.Arch,
+ Features: options.Features,
+ Images: options.Images,
+ OS: options.OS,
+ OSFeatures: nil,
+ OSVersion: options.OSVersion,
+ Variant: options.Variant,
+ Username: options.Username,
+ Password: options.Password,
+ Authfile: options.Authfile,
+ SkipTLSVerify: options.SkipTLSVerify,
}
optionsv4.WithOperation("update")
return Modify(ctx, name, options.Images, &optionsv4)
@@ -118,40 +126,27 @@ func Add(ctx context.Context, name string, options *AddOptions) (string, error)
}
reader := strings.NewReader(opts)
- headers := make(http.Header)
- v := version.APIVersion[version.Libpod][version.MinimalAPI]
- headers.Add("API-Version",
- fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch))
- response, err := conn.DoRequest(ctx, reader, http.MethodPost, "/manifests/%s/add", nil, headers, name)
+ header, err := auth.MakeXRegistryAuthHeader(&imageTypes.SystemContext{AuthFilePath: options.GetAuthfile()}, options.GetUsername(), options.GetPassword())
if err != nil {
return "", err
}
- defer response.Body.Close()
-
- var idr handlers.IDResponse
- return idr.ID, response.Process(&idr)
-}
-
-// Remove deletes a manifest entry from a manifest list. Both name and the digest to be
-// removed are mandatory inputs. The ID of the new manifest list is returned as a string.
-func Remove(ctx context.Context, name, digest string, _ *RemoveOptions) (string, error) {
- if bindings.ServiceVersion(ctx).GTE(semver.MustParse("4.0.0")) {
- optionsv4 := new(ModifyOptions).WithOperation("remove")
- return Modify(ctx, name, []string{digest}, optionsv4)
- }
- // API Version < 4.0.0
- conn, err := bindings.GetClient(ctx)
+ params, err := options.ToParams()
if err != nil {
return "", err
}
+ // SkipTLSVerify is special. We need to delete the param added by
+ // ToParams() and change the key and flip the bool
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
+ }
- headers := http.Header{}
- headers.Add("API-Version", "3.4.0")
+ v := version.APIVersion[version.Libpod][version.MinimalAPI]
+ header.Add("API-Version",
+ fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch))
- params := url.Values{}
- params.Set("digest", digest)
- response, err := conn.DoRequest(ctx, nil, http.MethodDelete, "/manifests/%s", params, headers, name)
+ response, err := conn.DoRequest(ctx, reader, http.MethodPost, "/manifests/%s/add", params, header, name)
if err != nil {
return "", err
}
@@ -161,6 +156,13 @@ func Remove(ctx context.Context, name, digest string, _ *RemoveOptions) (string,
return idr.ID, response.Process(&idr)
}
+// Remove deletes a manifest entry from a manifest list. Both name and the digest to be
+// removed are mandatory inputs. The ID of the new manifest list is returned as a string.
+func Remove(ctx context.Context, name, digest string, _ *RemoveOptions) (string, error) {
+ optionsv4 := new(ModifyOptions).WithOperation("remove")
+ return Modify(ctx, name, []string{digest}, optionsv4)
+}
+
// Push takes a manifest list and pushes to a destination. If the destination is not specified,
// the name will be used instead. If the optional all boolean is specified, all images specified
// in the list will be pushed as well.
@@ -179,6 +181,14 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt
return "", err
}
+ header, err := auth.MakeXRegistryAuthHeader(&imageTypes.SystemContext{AuthFilePath: options.GetAuthfile()}, options.GetUsername(), options.GetPassword())
+ if err != nil {
+ return "", err
+ }
+ v := version.APIVersion[version.Libpod][version.MinimalAPI]
+ header.Add("API-Version",
+ fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch))
+
params, err := options.ToParams()
if err != nil {
return "", err
@@ -192,18 +202,18 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt
var response *bindings.APIResponse
if bindings.ServiceVersion(ctx).GTE(semver.MustParse("4.0.0")) {
- response, err = conn.DoRequest(ctx, nil, http.MethodPost, "/manifests/%s/registry/%s", params, nil, name, destination)
+ response, err = conn.DoRequest(ctx, nil, http.MethodPost, "/manifests/%s/registry/%s", params, header, name, destination)
} else {
params.Set("image", name)
params.Set("destination", destination)
- response, err = conn.DoRequest(ctx, nil, http.MethodPost, "/manifests/%s/push", params, nil, name)
+ response, err = conn.DoRequest(ctx, nil, http.MethodPost, "/manifests/%s/push", params, header, name)
}
if err != nil {
return "", err
}
defer response.Body.Close()
- return idr.ID, err
+ return idr.ID, response.Process(&idr)
}
// Modify modifies the given manifest list using options and the optional list of images
@@ -223,14 +233,58 @@ func Modify(ctx context.Context, name string, images []string, options *ModifyOp
}
reader := strings.NewReader(opts)
- response, err := conn.DoRequest(ctx, reader, http.MethodPut, "/manifests/%s", nil, nil, name)
+ header, err := auth.MakeXRegistryAuthHeader(&imageTypes.SystemContext{AuthFilePath: options.GetAuthfile()}, options.GetUsername(), options.GetPassword())
+ if err != nil {
+ return "", err
+ }
+
+ params, err := options.ToParams()
+ if err != nil {
+ return "", err
+ }
+ // SkipTLSVerify is special. We need to delete the param added by
+ // ToParams() and change the key and flip the bool
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
+ }
+
+ response, err := conn.DoRequest(ctx, reader, http.MethodPut, "/manifests/%s", params, header, name)
if err != nil {
return "", err
}
defer response.Body.Close()
- var idr handlers.IDResponse
- return idr.ID, response.Process(&idr)
+ data, err := ioutil.ReadAll(response.Body)
+ if err != nil {
+ return "", errors.Wrap(err, "unable to process API response")
+ }
+
+ if response.IsSuccess() || response.IsRedirection() {
+ var report entities.ManifestModifyReport
+ if err = jsoniter.Unmarshal(data, &report); err != nil {
+ return "", errors.Wrap(err, "unable to decode API response")
+ }
+
+ err = errorhandling.JoinErrors(report.Errors)
+ if err != nil {
+ errModel := errorhandling.ErrorModel{
+ Because: (errors.Cause(err)).Error(),
+ Message: err.Error(),
+ ResponseCode: response.StatusCode,
+ }
+ return report.ID, &errModel
+ }
+ return report.ID, nil
+ }
+
+ errModel := errorhandling.ErrorModel{
+ ResponseCode: response.StatusCode,
+ }
+ if err = jsoniter.Unmarshal(data, &errModel); err != nil {
+ return "", errors.Wrap(err, "unable to decode API response")
+ }
+ return "", &errModel
}
// Annotate modifies the given manifest list using options and the optional list of images
diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go
index 5ff28ee30..d0b0b2e71 100644
--- a/pkg/bindings/manifests/types.go
+++ b/pkg/bindings/manifests/types.go
@@ -20,14 +20,18 @@ type ExistsOptions struct {
//go:generate go run ../generator/generator.go AddOptions
// AddOptions are optional options for adding manifest lists
type AddOptions struct {
- All *bool
- Annotation map[string]string
- Arch *string
- Features []string
- Images []string
- OS *string
- OSVersion *string
- Variant *string
+ All *bool
+ Annotation map[string]string
+ Arch *string
+ Features []string
+ Images []string
+ OS *string
+ OSVersion *string
+ Variant *string
+ Authfile *string
+ Password *string
+ Username *string
+ SkipTLSVerify *bool
}
//go:generate go run ../generator/generator.go RemoveOptions
@@ -40,15 +44,18 @@ type RemoveOptions struct {
type ModifyOptions struct {
// Operation values are "update", "remove" and "annotate". This allows the service to
// efficiently perform each update on a manifest list.
- Operation *string
- All *bool // All when true, operate on all images in a manifest list that may be included in Images
- Annotations map[string]string // Annotations to add to manifest list
- Arch *string // Arch overrides the architecture for the image
- Features []string // Feature list for the image
- Images []string // Images is an optional list of images to add/remove to/from manifest list depending on operation
- OS *string // OS overrides the operating system for the image
- OSFeatures []string // OS features for the image
- OSVersion *string // OSVersion overrides the operating system for the image
- Variant *string // Variant overrides the operating system variant for the image
-
+ Operation *string
+ All *bool // All when true, operate on all images in a manifest list that may be included in Images
+ Annotations map[string]string // Annotations to add to manifest list
+ Arch *string // Arch overrides the architecture for the image
+ Features []string // Feature list for the image
+ Images []string // Images is an optional list of images to add/remove to/from manifest list depending on operation
+ OS *string // OS overrides the operating system for the image
+ OSFeatures []string // OS features for the image
+ OSVersion *string // OSVersion overrides the operating system for the image
+ Variant *string // Variant overrides the operating system variant for the image
+ Authfile *string
+ Password *string
+ Username *string
+ SkipTLSVerify *bool
}
diff --git a/pkg/bindings/manifests/types_add_options.go b/pkg/bindings/manifests/types_add_options.go
index 0696a69b6..5ba1cc5fa 100644
--- a/pkg/bindings/manifests/types_add_options.go
+++ b/pkg/bindings/manifests/types_add_options.go
@@ -136,3 +136,63 @@ func (o *AddOptions) GetVariant() string {
}
return *o.Variant
}
+
+// WithAuthfile set field Authfile to given value
+func (o *AddOptions) WithAuthfile(value string) *AddOptions {
+ o.Authfile = &value
+ return o
+}
+
+// GetAuthfile returns value of field Authfile
+func (o *AddOptions) GetAuthfile() string {
+ if o.Authfile == nil {
+ var z string
+ return z
+ }
+ return *o.Authfile
+}
+
+// WithPassword set field Password to given value
+func (o *AddOptions) WithPassword(value string) *AddOptions {
+ o.Password = &value
+ return o
+}
+
+// GetPassword returns value of field Password
+func (o *AddOptions) GetPassword() string {
+ if o.Password == nil {
+ var z string
+ return z
+ }
+ return *o.Password
+}
+
+// WithUsername set field Username to given value
+func (o *AddOptions) WithUsername(value string) *AddOptions {
+ o.Username = &value
+ return o
+}
+
+// GetUsername returns value of field Username
+func (o *AddOptions) GetUsername() string {
+ if o.Username == nil {
+ var z string
+ return z
+ }
+ return *o.Username
+}
+
+// WithSkipTLSVerify set field SkipTLSVerify to given value
+func (o *AddOptions) WithSkipTLSVerify(value bool) *AddOptions {
+ o.SkipTLSVerify = &value
+ return o
+}
+
+// GetSkipTLSVerify returns value of field SkipTLSVerify
+func (o *AddOptions) GetSkipTLSVerify() bool {
+ if o.SkipTLSVerify == nil {
+ var z bool
+ return z
+ }
+ return *o.SkipTLSVerify
+}
diff --git a/pkg/bindings/manifests/types_modify_options.go b/pkg/bindings/manifests/types_modify_options.go
index 6d75c1e5f..9d2ed2613 100644
--- a/pkg/bindings/manifests/types_modify_options.go
+++ b/pkg/bindings/manifests/types_modify_options.go
@@ -166,3 +166,63 @@ func (o *ModifyOptions) GetVariant() string {
}
return *o.Variant
}
+
+// WithAuthfile set field Authfile to given value
+func (o *ModifyOptions) WithAuthfile(value string) *ModifyOptions {
+ o.Authfile = &value
+ return o
+}
+
+// GetAuthfile returns value of field Authfile
+func (o *ModifyOptions) GetAuthfile() string {
+ if o.Authfile == nil {
+ var z string
+ return z
+ }
+ return *o.Authfile
+}
+
+// WithPassword set field Password to given value
+func (o *ModifyOptions) WithPassword(value string) *ModifyOptions {
+ o.Password = &value
+ return o
+}
+
+// GetPassword returns value of field Password
+func (o *ModifyOptions) GetPassword() string {
+ if o.Password == nil {
+ var z string
+ return z
+ }
+ return *o.Password
+}
+
+// WithUsername set field Username to given value
+func (o *ModifyOptions) WithUsername(value string) *ModifyOptions {
+ o.Username = &value
+ return o
+}
+
+// GetUsername returns value of field Username
+func (o *ModifyOptions) GetUsername() string {
+ if o.Username == nil {
+ var z string
+ return z
+ }
+ return *o.Username
+}
+
+// WithSkipTLSVerify set field SkipTLSVerify to given value
+func (o *ModifyOptions) WithSkipTLSVerify(value bool) *ModifyOptions {
+ o.SkipTLSVerify = &value
+ return o
+}
+
+// GetSkipTLSVerify returns value of field SkipTLSVerify
+func (o *ModifyOptions) GetSkipTLSVerify() bool {
+ if o.SkipTLSVerify == nil {
+ var z bool
+ return z
+ }
+ return *o.SkipTLSVerify
+}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index d4018b6b3..8058a8514 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -2,6 +2,7 @@ package play
import (
"context"
+ "io"
"net/http"
"os"
"strconv"
@@ -14,20 +15,25 @@ import (
)
func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return KubeWithBody(ctx, f, options)
+}
+
+func KubeWithBody(ctx context.Context, body io.Reader, options *KubeOptions) (*entities.PlayKubeReport, error) {
var report entities.PlayKubeReport
if options == nil {
options = new(KubeOptions)
}
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
- f, err := os.Open(path)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- defer f.Close()
params, err := options.ToParams()
if err != nil {
@@ -46,7 +52,7 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
return nil, err
}
- response, err := conn.DoRequest(ctx, f, http.MethodPost, "/play/kube", params, header)
+ response, err := conn.DoRequest(ctx, body, http.MethodPost, "/play/kube", params, header)
if err != nil {
return nil, err
}
@@ -60,12 +66,6 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
}
func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error) {
- var report entities.PlayKubeReport
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
-
f, err := os.Open(path)
if err != nil {
return nil, err
@@ -75,7 +75,18 @@ func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error
logrus.Warn(err)
}
}()
- response, err := conn.DoRequest(ctx, f, http.MethodDelete, "/play/kube", nil, nil)
+
+ return KubeDownWithBody(ctx, f)
+}
+
+func KubeDownWithBody(ctx context.Context, body io.Reader) (*entities.PlayKubeReport, error) {
+ var report entities.PlayKubeReport
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(ctx, body, http.MethodDelete, "/play/kube", nil, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go
index 670566882..dcebe0809 100644
--- a/pkg/bindings/test/attach_test.go
+++ b/pkg/bindings/test/attach_test.go
@@ -44,7 +44,8 @@ var _ = Describe("Podman containers attach", func() {
timeout := uint(5)
err := containers.Stop(bt.conn, id, new(containers.StopOptions).WithTimeout(timeout))
if err != nil {
- GinkgoWriter.Write([]byte(err.Error()))
+ _, writeErr := GinkgoWriter.Write([]byte(err.Error()))
+ Expect(writeErr).ShouldNot(HaveOccurred())
}
}()
diff --git a/pkg/bindings/test/auth_test.go b/pkg/bindings/test/auth_test.go
index b421f0797..c4c4b16d8 100644
--- a/pkg/bindings/test/auth_test.go
+++ b/pkg/bindings/test/auth_test.go
@@ -40,7 +40,8 @@ var _ = Describe("Podman images", func() {
AfterEach(func() {
s.Kill()
bt.cleanup()
- registry.Stop()
+ err := registry.Stop()
+ Expect(err).To(BeNil())
})
// Test using credentials.
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index f51e5f404..f2602967b 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -211,7 +211,7 @@ func (b *bindingTest) RunTopContainer(containerName *string, podName *string) (s
}
ctr, err := containers.CreateWithSpec(b.conn, s, nil)
if err != nil {
- return "", nil
+ return "", err
}
err = containers.Start(b.conn, ctr.ID, nil)
if err != nil {
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 9411d8a5f..bf627fdba 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -322,7 +322,8 @@ var _ = Describe("Podman containers ", func() {
// a container that has no healthcheck should be a 409
var name = "top"
- bt.RunTopContainer(&name, nil)
+ _, err = bt.RunTopContainer(&name, nil)
+ Expect(err).To(BeNil())
_, err = containers.RunHealthCheck(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
diff --git a/pkg/checkpoint/crutils/checkpoint_restore_utils.go b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
index 2765d18e8..6a8a7894a 100644
--- a/pkg/checkpoint/crutils/checkpoint_restore_utils.go
+++ b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
@@ -99,13 +99,12 @@ func CRRemoveDeletedFiles(id, baseDirectory, containerRootDirectory string) erro
// root file system changes on top of containerRootDirectory
func CRApplyRootFsDiffTar(baseDirectory, containerRootDirectory string) error {
rootfsDiffPath := filepath.Join(baseDirectory, metadata.RootFsDiffTar)
- if _, err := os.Stat(rootfsDiffPath); err != nil {
- // Only do this if a rootfs-diff.tar actually exists
- return nil
- }
-
+ // Only do this if a rootfs-diff.tar actually exists
rootfsDiffFile, err := os.Open(rootfsDiffPath)
if err != nil {
+ if errors.Is(err, os.ErrNotExist) {
+ return nil
+ }
return errors.Wrap(err, "failed to open root file-system diff file")
}
defer rootfsDiffFile.Close()
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 7cf7ca17f..6b70a3452 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -68,8 +68,8 @@ type ContainerEngine interface {
NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, 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)
- PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error)
+ PlayKube(ctx context.Context, body io.Reader, opts PlayKubeOptions) (*PlayKubeReport, error)
+ PlayKubeDown(ctx context.Context, body io.Reader, opts PlayKubeDownOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 2ac21cfeb..7081c5d25 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -90,6 +90,8 @@ type ImageRemoveOptions struct {
All bool
// Foce will force image removal including containers using the images.
Force bool
+ // Ignore if a specified image does not exist and do not throw an error.
+ Ignore bool
// Confirms if given name is a manifest list and removes it, otherwise returns error.
LookupManifest bool
}
@@ -277,6 +279,7 @@ type ImageLoadReport struct {
type ImageImportOptions struct {
Architecture string
+ Variant string
Changes []string
Message string
OS string
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index 4d9ced900..bed3183e9 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -20,7 +20,7 @@ type Volume struct {
}
type Report struct {
- Id []string //nolint
+ Id []string // nolint
Err map[string]error
}
@@ -98,8 +98,10 @@ type EventsOptions struct {
// ContainerCreateResponse is the response struct for creating a container
type ContainerCreateResponse struct {
// ID of the container created
+ // required: true
ID string `json:"Id"`
// Warnings during container creation
+ // required: true
Warnings []string `json:"Warnings"`
}
diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go
index 85ba4f84f..4c6964a00 100644
--- a/pkg/domain/filters/containers.go
+++ b/pkg/domain/filters/containers.go
@@ -213,8 +213,10 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
for _, val := range filterValues {
net, err := r.Network().NetworkInspect(val)
if err != nil {
- // ignore not found errors
- break
+ if errors.Is(err, define.ErrNoSuchNetwork) {
+ continue
+ }
+ return nil, err
}
inputNetNames = append(inputNetNames, net.Name)
}
diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go
index 2f9442dff..e22480006 100644
--- a/pkg/domain/filters/pods.go
+++ b/pkg/domain/filters/pods.go
@@ -131,8 +131,10 @@ func GeneratePodFilterFunc(filter string, filterValues []string, r *libpod.Runti
for _, val := range filterValues {
net, err := r.Network().NetworkInspect(val)
if err != nil {
- // ignore not found errors
- break
+ if errors.Is(err, define.ErrNoSuchNetwork) {
+ continue
+ }
+ return nil, err
}
inputNetNames = append(inputNetNames, net.Name)
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index e6feb7c82..f45bdeba5 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1431,12 +1431,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
reportStats := []define.ContainerStats{}
for _, ctr := range containers {
- prev, ok := containerStats[ctr.ID()]
- if !ok {
- prev = &define.ContainerStats{}
- }
-
- stats, err := ctr.GetContainerStats(prev)
+ stats, err := ctr.GetContainerStats(containerStats[ctr.ID()])
if err != nil {
cause := errors.Cause(err)
if queryAll && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
@@ -1501,6 +1496,35 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti
return nil, err
}
+ if ctrCloneOpts.CreateOpts.Pod != "" {
+ pod, err := ic.Libpod.LookupPod(ctrCloneOpts.CreateOpts.Pod)
+ if err != nil {
+ return nil, err
+ }
+
+ allNamespaces := []struct {
+ isShared bool
+ value *specgen.Namespace
+ }{
+ {pod.SharesPID(), &spec.PidNS},
+ {pod.SharesNet(), &spec.NetNS},
+ {pod.SharesCgroup(), &spec.CgroupNS},
+ {pod.SharesIPC(), &spec.IpcNS},
+ {pod.SharesUTS(), &spec.UtsNS},
+ }
+
+ printWarning := false
+ for _, n := range allNamespaces {
+ if n.isShared && !n.value.IsDefault() {
+ *n.value = specgen.Namespace{NSMode: specgen.Default}
+ printWarning = true
+ }
+ }
+ if printWarning {
+ logrus.Warning("At least one namespace was reset to the default configuration")
+ }
+ }
+
err = specgenutil.FillOutSpecGen(spec, &ctrCloneOpts.CreateOpts, []string{})
if err != nil {
return nil, err
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 0b1281aac..74478b26d 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -445,7 +445,8 @@ func (ir *ImageEngine) Import(ctx context.Context, options entities.ImageImportO
importOptions.Tag = options.Reference
importOptions.SignaturePolicyPath = options.SignaturePolicy
importOptions.OS = options.OS
- importOptions.Architecture = options.Architecture
+ importOptions.Arch = options.Architecture
+ importOptions.Variant = options.Variant
if !options.Quiet {
importOptions.Writer = os.Stderr
@@ -578,6 +579,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
libimageOptions := &libimage.RemoveImagesOptions{}
libimageOptions.Filters = []string{"readonly=false"}
libimageOptions.Force = opts.Force
+ libimageOptions.Ignore = opts.Ignore
libimageOptions.LookupManifest = opts.LookupManifest
if !opts.All {
libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false")
@@ -847,13 +849,12 @@ func execPodman(execUser *user.User, command []string) error {
if err != nil {
return err
}
- defer func() error {
- err := cmdLogin.Process.Kill()
- if err != nil {
- return err
- }
- return cmdLogin.Wait()
+
+ defer func() {
+ _ = cmdLogin.Process.Kill()
+ _ = cmdLogin.Wait()
}()
+
cmd := exec.Command(command[0], command[1:]...)
cmd.Env = []string{"PATH=" + os.Getenv("PATH"), "TERM=" + os.Getenv("TERM")}
cmd.Stderr = os.Stderr
diff --git a/pkg/domain/infra/abi/images_test.go b/pkg/domain/infra/abi/images_test.go
index e38b9390d..311ab3ed7 100644
--- a/pkg/domain/infra/abi/images_test.go
+++ b/pkg/domain/infra/abi/images_test.go
@@ -48,7 +48,7 @@ func TestToDomainHistoryLayer(t *testing.T) {
// r := DirectImageRuntime{m}
// err := r.Delete(context.TODO(), actual, "fedora")
// if err != nil {
-// t.Errorf("error should be nil, got: %v", err)
+// t.Errorf("should be nil, got: %v", err)
// }
// m.AssertExpectations(t)
// }
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 4d8c5a381..1423ab06e 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -33,12 +33,12 @@ import (
yamlv2 "gopkg.in/yaml.v2"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
report := &entities.PlayKubeReport{}
validKinds := 0
// read yaml document
- content, err := ioutil.ReadFile(path)
+ content, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
@@ -52,7 +52,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
// sort kube kinds
documentList, err = sortKubeKinds(documentList)
if err != nil {
- return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ return nil, errors.Wrap(err, "unable to sort kube kinds")
}
ipIndex := 0
@@ -64,7 +64,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
- return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ return nil, errors.Wrap(err, "unable to read kube YAML")
}
switch kind {
@@ -73,7 +73,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var podTemplateSpec v1.PodTemplateSpec
if err := yaml.Unmarshal(document, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Pod")
}
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
@@ -97,7 +97,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment")
}
r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps)
@@ -111,7 +111,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var pvcYAML v1.PersistentVolumeClaim
if err := yaml.Unmarshal(document, &pvcYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube PersistentVolumeClaim", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube PersistentVolumeClaim")
}
r, err := ic.playKubePVC(ctx, &pvcYAML, options)
@@ -125,7 +125,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var configMap v1.ConfigMap
if err := yaml.Unmarshal(document, &configMap); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube ConfigMap", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube ConfigMap")
}
configMaps = append(configMaps, configMap)
default:
@@ -215,7 +215,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
// FIXME This is very hard to support properly with a good ux
if len(options.StaticIPs) > *ipIndex {
if !podOpt.Net.Network.IsBridge() {
- errors.Wrap(define.ErrInvalidArg, "static ip addresses can only be set when the network mode is bridge")
+ return nil, errors.Wrap(define.ErrInvalidArg, "static ip addresses can only be set when the network mode is bridge")
}
if len(podOpt.Net.Networks) != 1 {
return nil, errors.Wrap(define.ErrInvalidArg, "cannot set static ip addresses for more than network, use netname:ip=<ip> syntax to specify ips for more than network")
@@ -230,7 +230,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
if len(options.StaticMACs) > *ipIndex {
if !podOpt.Net.Network.IsBridge() {
- errors.Wrap(define.ErrInvalidArg, "static mac address can only be set when the network mode is bridge")
+ return nil, errors.Wrap(define.ErrInvalidArg, "static mac address can only be set when the network mode is bridge")
}
if len(podOpt.Net.Networks) != 1 {
return nil, errors.Wrap(define.ErrInvalidArg, "cannot set static mac address for more than network, use netname:mac=<mac> syntax to specify mac for more than network")
@@ -773,14 +773,14 @@ func getBuildFile(imageName string, cwd string) (string, error) {
return "", err
}
-func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
var (
podNames []string
)
reports := new(entities.PlayKubeReport)
// read yaml document
- content, err := ioutil.ReadFile(path)
+ content, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
@@ -794,27 +794,27 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ enti
// sort kube kinds
documentList, err = sortKubeKinds(documentList)
if err != nil {
- return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ return nil, errors.Wrap(err, "unable to sort kube kinds")
}
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
- return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ return nil, errors.Wrap(err, "unable to read as kube YAML")
}
switch kind {
case "Pod":
var podYAML v1.Pod
if err := yaml.Unmarshal(document, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Pod")
}
podNames = append(podNames, podYAML.ObjectMeta.Name)
case "Deployment":
var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment")
}
var numReplicas int32 = 1
deploymentName := deploymentYAML.ObjectMeta.Name
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index d12d14c1f..4361821d5 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -6,7 +6,6 @@ import (
"net/url"
"os"
"os/exec"
- "path/filepath"
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/config"
@@ -269,7 +268,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
}
dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols))
- var reclaimableSize int64
+ var reclaimableSize uint64
for _, v := range vols {
var consInUse int
mountPoint, err := v.MountPoint()
@@ -282,7 +281,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
// TODO: fix this.
continue
}
- volSize, err := sizeOfPath(mountPoint)
+ volSize, err := util.SizeOfPath(mountPoint)
if err != nil {
return nil, err
}
@@ -301,8 +300,8 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
report := entities.SystemDfVolumeReport{
VolumeName: v.Name(),
Links: consInUse,
- Size: volSize,
- ReclaimableSize: reclaimableSize,
+ Size: int64(volSize),
+ ReclaimableSize: int64(reclaimableSize),
}
dfVolumes = append(dfVolumes, &report)
}
@@ -313,19 +312,6 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
}, nil
}
-// sizeOfPath determines the file usage of a given path. it was called volumeSize in v1
-// and now is made to be generic and take a path instead of a libpod volume
-func sizeOfPath(path string) (int64, error) {
- var size int64
- err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
- if err == nil && !info.IsDir() {
- size += info.Size()
- }
- return err
- })
- return size, err
-}
-
func (se *SystemEngine) Reset(ctx context.Context) error {
return se.Libpod.Reset(ctx)
}
diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
index 206ded091..fe2c268c0 100644
--- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go
+++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
@@ -20,7 +20,7 @@ const signalBufferSize = 2048
func ProxySignals(ctr *libpod.Container) {
// Stop catching the shutdown signals (SIGINT, SIGTERM) - they're going
// to the container now.
- shutdown.Stop()
+ shutdown.Stop() // nolint: errcheck
sigBuffer := make(chan os.Signal, signalBufferSize)
signal.CatchAll(sigBuffer)
diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go
index 78c792d2b..153b19fdb 100644
--- a/pkg/domain/infra/abi/terminal/terminal_linux.go
+++ b/pkg/domain/infra/abi/terminal/terminal_linux.go
@@ -39,7 +39,7 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpo
// StartAttachCtr starts and (if required) attaches to a container
// if you change the signature of this function from os.File to io.Writer, it will trigger a downstream
// error. we may need to just lint disable this one.
-func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error { //nolint-interfacer
+func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error { //nolint: interfacer
resize := make(chan define.TerminalSize)
haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index 19fc6d2d3..f59f11e20 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -171,7 +171,8 @@ func (ic *ContainerEngine) VolumeMounted(ctx context.Context, nameOrID string) (
}
mountCount, err := vol.MountCount()
if err != nil {
- return &entities.BoolReport{Value: false}, nil
+ // FIXME: this error should probably be returned
+ return &entities.BoolReport{Value: false}, nil // nolint: nilerr
}
if mountCount > 0 {
return &entities.BoolReport{Value: true}, nil
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 046c2509d..10bfb3984 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -840,7 +840,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if eventsErr != nil || lastEvent == nil {
logrus.Errorf("Cannot get exit code: %v", err)
report.ExitCode = define.ExecErrorCodeNotFound
- return &report, nil // compat with local client
+ return &report, nil // nolint: nilerr
}
report.ExitCode = lastEvent.ContainerExitCode
@@ -938,7 +938,7 @@ func (ic *ContainerEngine) ContainerStat(ctx context.Context, nameOrID string, p
return containers.Stat(ic.ClientCtx, nameOrID, path)
}
-// Shutdown Libpod engine
+// Shutdown Libpod engine.
func (ic *ContainerEngine) Shutdown(_ context.Context) {
}
@@ -949,7 +949,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
return containers.Stats(ic.ClientCtx, namesOrIds, new(containers.StatsOptions).WithStream(options.Stream).WithInterval(options.Interval))
}
-// ShouldRestart reports back whether the container will restart
+// ShouldRestart reports back whether the container will restart.
func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
return containers.ShouldRestart(ic.ClientCtx, id, nil)
}
diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go
index 1f27cdff8..b472ad03a 100644
--- a/pkg/domain/infra/tunnel/events.go
+++ b/pkg/domain/infra/tunnel/events.go
@@ -34,7 +34,7 @@ func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptio
}
// GetLastContainerEvent takes a container name or ID and an event status and returns
-// the last occurrence of the container event
+// the last occurrence of the container event.
func (ic *ContainerEngine) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
// check to make sure the event.Status is valid
if _, err := events.StringToStatus(containerEvent.String()); err != nil {
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 3ee97d94c..18e10e8dd 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -28,7 +28,7 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
}
func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
- options := new(images.RemoveOptions).WithForce(opts.Force).WithAll(opts.All)
+ options := new(images.RemoveOptions).WithForce(opts.Force).WithIgnore(opts.Ignore).WithAll(opts.All)
return images.Remove(ir.ClientCtx, imagesArg, options)
}
@@ -230,6 +230,7 @@ func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOpti
f *os.File
)
options := new(images.ImportOptions).WithChanges(opts.Changes).WithMessage(opts.Message).WithReference(opts.Reference)
+ options.WithOS(opts.OS).WithArchitecture(opts.Architecture).WithVariant(opts.Variant)
if opts.SourceIsURL {
options.WithURL(opts.Source)
} else {
diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go
index d2efed8d3..9ac3fdb83 100644
--- a/pkg/domain/infra/tunnel/manifest.go
+++ b/pkg/domain/infra/tunnel/manifest.go
@@ -50,6 +50,7 @@ func (ir *ImageEngine) ManifestInspect(_ context.Context, name string) ([]byte,
func (ir *ImageEngine) ManifestAdd(_ context.Context, name string, imageNames []string, opts entities.ManifestAddOptions) (string, error) {
options := new(manifests.AddOptions).WithAll(opts.All).WithArch(opts.Arch).WithVariant(opts.Variant)
options.WithFeatures(opts.Features).WithImages(imageNames).WithOS(opts.OS).WithOSVersion(opts.OSVersion)
+ options.WithUsername(opts.Username).WithPassword(opts.Password).WithAuthfile(opts.Authfile)
if len(opts.Annotation) != 0 {
annotations := make(map[string]string)
for _, annotationSpec := range opts.Annotation {
@@ -61,6 +62,13 @@ func (ir *ImageEngine) ManifestAdd(_ context.Context, name string, imageNames []
}
options.WithAnnotation(annotations)
}
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
id, err := manifests.Add(ir.ClientCtx, name, options)
if err != nil {
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index cd51262d0..d9637254a 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -2,13 +2,14 @@ package tunnel
import (
"context"
+ "io"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/bindings/play"
"github.com/containers/podman/v4/pkg/domain/entities"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password)
options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Networks).WithSeccompProfileRoot(opts.SeccompProfileRoot)
@@ -26,9 +27,9 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit
if start := opts.Start; start != types.OptionalBoolUndefined {
options.WithStart(start == types.OptionalBoolTrue)
}
- return play.Kube(ic.ClientCtx, path, options)
+ return play.KubeWithBody(ic.ClientCtx, body, options)
}
-func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
- return play.KubeDown(ic.ClientCtx, path)
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+ return play.KubeDownWithBody(ic.ClientCtx, body)
}
diff --git a/pkg/env/env.go b/pkg/env/env.go
index ecd2d62a5..5989d0da5 100644
--- a/pkg/env/env.go
+++ b/pkg/env/env.go
@@ -26,7 +26,7 @@ func DefaultEnvVariables() map[string]string {
// Slice transforms the specified map of environment variables into a
// slice. If a value is non-empty, the key and value are joined with '='.
func Slice(m map[string]string) []string {
- env := make([]string, len(m))
+ env := make([]string, 0, len(m))
for k, v := range m {
var s string
if len(v) > 0 {
diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go
index 04110b62a..e33c26032 100644
--- a/pkg/errorhandling/errorhandling.go
+++ b/pkg/errorhandling/errorhandling.go
@@ -28,7 +28,7 @@ func JoinErrors(errs []error) error {
finalErr := multiE.ErrorOrNil()
if finalErr == nil {
- return finalErr
+ return nil
}
return errors.New(strings.TrimSpace(finalErr.Error()))
}
diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go
index cd26db6b0..767d86daf 100644
--- a/pkg/inspect/inspect.go
+++ b/pkg/inspect/inspect.go
@@ -9,7 +9,7 @@ import (
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
-// ImageData holds the inspect information of an image
+// ImageData holds the inspect information of an image.
type ImageData struct {
ID string `json:"Id"`
Digest digest.Digest `json:"Digest"`
@@ -36,13 +36,13 @@ type ImageData struct {
HealthCheck *manifest.Schema2HealthConfig `json:"Healthcheck,omitempty"`
}
-// RootFS holds the root fs information of an image
+// RootFS holds the root fs information of an image.
type RootFS struct {
Type string `json:"Type"`
Layers []digest.Digest `json:"Layers"`
}
-// ImageResult is used for podman images for collection and output
+// ImageResult is used for podman images for collection and output.
type ImageResult struct {
Tag string
Repository string
diff --git a/pkg/k8s.io/api/core/v1/types.go b/pkg/k8s.io/api/core/v1/types.go
index 833814bc6..a488e5f28 100644
--- a/pkg/k8s.io/api/core/v1/types.go
+++ b/pkg/k8s.io/api/core/v1/types.go
@@ -2024,7 +2024,7 @@ type TopologySpreadConstraint struct {
// but giving higher precedence to topologies that would help reduce the
// skew.
// A constraint is considered "Unsatisfiable" for an incoming pod
- // if and only if every possible node assigment for that pod would violate
+ // if and only if every possible node assignment for that pod would violate
// "MaxSkew" on some topology.
// For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
// labelSelector spread as 3/1/1:
diff --git a/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go b/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go
index fccddc3e0..352cc028f 100644
--- a/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go
+++ b/pkg/k8s.io/apimachinery/pkg/api/resource/quantity.go
@@ -579,9 +579,9 @@ func (q Quantity) MarshalJSON() ([]byte, error) {
// if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use
// append
result = result[:1]
- result = append(result, number...)
- result = append(result, suffix...)
- result = append(result, '"')
+ result = append(result, number...) // nolint: makezero
+ result = append(result, suffix...) // nolint: makezero
+ result = append(result, '"') // nolint: makezero
return result, nil
}
diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go
index 0b22a1974..0601e829d 100644
--- a/pkg/lookup/lookup.go
+++ b/pkg/lookup/lookup.go
@@ -14,7 +14,7 @@ const (
etcgroup = "/etc/group"
)
-// Overrides allows you to override defaults in GetUserGroupInfo
+// Overrides allows you to override defaults in GetUserGroupInfo.
type Overrides struct {
DefaultUser *user.ExecUser
ContainerEtcPasswdPath string
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index b3b105150..7e1561506 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -29,16 +29,16 @@ type InitOptions struct {
Username string
ReExec bool
Rootful bool
- // The numberical userid of the user that called machine
+ // The numerical userid of the user that called machine
UID string
}
type QemuMachineStatus = string
const (
- // Running indicates the qemu vm is running
+ // Running indicates the qemu vm is running.
Running QemuMachineStatus = "running"
- // Stopped indicates the vm has stopped
+ // Stopped indicates the vm has stopped.
Stopped QemuMachineStatus = "stopped"
DefaultMachineName string = "podman-machine-default"
)
@@ -128,6 +128,7 @@ type DistributionDownload interface {
}
func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL {
+ //TODO Should this function have input verification?
userInfo := url.User(userName)
uri := url.URL{
Scheme: "ssh",
@@ -147,7 +148,7 @@ func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url
}
// GetDataDir returns the filepath where vm images should
-// live for podman-machine
+// live for podman-machine.
func GetDataDir(vmType string) (string, error) {
data, err := homedir.GetDataHome()
if err != nil {
diff --git a/pkg/machine/config_test.go b/pkg/machine/config_test.go
new file mode 100644
index 000000000..d9fc5425e
--- /dev/null
+++ b/pkg/machine/config_test.go
@@ -0,0 +1,71 @@
+package machine
+
+import (
+ "net"
+ "net/url"
+ "reflect"
+ "testing"
+)
+
+func TestRemoteConnectionType_MakeSSHURL(t *testing.T) {
+ var (
+ host = "foobar"
+ path = "/path/to/socket"
+ rc = "ssh"
+ username = "core"
+ )
+ type args struct {
+ host string
+ path string
+ port string
+ userName string
+ }
+ tests := []struct {
+ name string
+ rc RemoteConnectionType
+ args args
+ want url.URL
+ }{
+ {
+ name: "Good no port",
+ rc: "ssh",
+ args: args{
+ host: host,
+ path: path,
+ port: "",
+ userName: username,
+ },
+ want: url.URL{
+ Scheme: rc,
+ User: url.User(username),
+ Host: host,
+ Path: path,
+ ForceQuery: false,
+ },
+ },
+ {
+ name: "Good with port",
+ rc: "ssh",
+ args: args{
+ host: host,
+ path: path,
+ port: "222",
+ userName: username,
+ },
+ want: url.URL{
+ Scheme: rc,
+ User: url.User(username),
+ Host: net.JoinHostPort(host, "222"),
+ Path: path,
+ ForceQuery: false,
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := tt.rc.MakeSSHURL(tt.args.host, tt.args.path, tt.args.port, tt.args.userName); !reflect.DeepEqual(got, tt.want) { //nolint: scopelint
+ t.Errorf("MakeSSHURL() = %v, want %v", got, tt.want) //nolint: scopelint
+ }
+ })
+ }
+}
diff --git a/pkg/machine/fedora.go b/pkg/machine/fedora.go
index b26921b52..bed45c6da 100644
--- a/pkg/machine/fedora.go
+++ b/pkg/machine/fedora.go
@@ -59,7 +59,10 @@ func (f FedoraDownload) Get() *Download {
func (f FedoraDownload) HasUsableCache() (bool, error) {
info, err := os.Stat(f.LocalPath)
if err != nil {
- return false, nil
+ if errors.Is(err, os.ErrNotExist) {
+ return false, nil
+ }
+ return false, err
}
return info.Size() == f.Size, nil
}
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index b2dabb689..fe47437e3 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -6,6 +6,7 @@ package machine
import (
"encoding/json"
"fmt"
+ "io/fs"
"io/ioutil"
"net/url"
"os"
@@ -507,8 +508,8 @@ func getCerts(certsDir string, isDir bool) []File {
)
if isDir {
- err := filepath.Walk(certsDir, func(path string, info os.FileInfo, err error) error {
- if err == nil && !info.IsDir() {
+ err := filepath.WalkDir(certsDir, func(path string, d fs.DirEntry, err error) error {
+ if err == nil && !d.IsDir() {
certPath, err := filepath.Rel(certsDir, path)
if err != nil {
logrus.Warnf("%s", err)
diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go
index 26abedfcd..7e6f01bad 100644
--- a/pkg/machine/pull.go
+++ b/pkg/machine/pull.go
@@ -129,7 +129,7 @@ func DownloadVMImage(downloadURL *url2.URL, localImagePath string) error {
}()
if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("error downloading VM image %s: %s", downloadURL, resp.Status)
+ return fmt.Errorf("downloading VM image %s: %s", downloadURL, resp.Status)
}
size := resp.ContentLength
urlSplit := strings.Split(downloadURL.Path, "/")
diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go
index b39334be0..408b33a33 100644
--- a/pkg/machine/qemu/config.go
+++ b/pkg/machine/qemu/config.go
@@ -4,12 +4,28 @@
package qemu
import (
+ "errors"
+ "os"
"time"
+
+ "github.com/sirupsen/logrus"
+)
+
+const (
+ // FCOS streams
+ // Testing FCOS stream
+ Testing string = "testing"
+ // Next FCOS stream
+ Next string = "next"
+ // Stable FCOS stream
+ Stable string = "stable"
)
type Provider struct{}
-type MachineVM struct {
+// Deprecated: MachineVMV1 is being deprecated in favor a more flexible and informative
+// structure
+type MachineVMV1 struct {
// CPUs to be assigned to the VM
CPUs uint64
// The command line representation of the qemu command
@@ -42,6 +58,74 @@ type MachineVM struct {
UID int
}
+type MachineVM struct {
+ // The command line representation of the qemu command
+ CmdLine []string
+ // HostUser contains info about host user
+ HostUser
+ // ImageConfig describes the bootable image
+ ImageConfig
+ // Mounts is the list of remote filesystems to mount
+ Mounts []Mount
+ // Name of VM
+ Name string
+ // PidFilePath is the where the PID file lives
+ PidFilePath MachineFile
+ // QMPMonitor is the qemu monitor object for sending commands
+ QMPMonitor Monitor
+ // ReadySocket tells host when vm is booted
+ ReadySocket MachineFile
+ // ResourceConfig is physical attrs of the VM
+ ResourceConfig
+ // SSHConfig for accessing the remote vm
+ SSHConfig
+}
+
+// ImageConfig describes the bootable image for the VM
+type ImageConfig struct {
+ IgnitionFilePath string
+ // ImageStream is the update stream for the image
+ ImageStream string
+ // ImagePath is the fq path to
+ ImagePath string
+}
+
+// HostUser describes the host user
+type HostUser struct {
+ // Whether this machine should run in a rootful or rootless manner
+ Rootful bool
+ // UID is the numerical id of the user that called machine
+ UID int
+}
+
+// SSHConfig contains remote access information for SSH
+type SSHConfig struct {
+ // IdentityPath is the fq path to the ssh priv key
+ IdentityPath string
+ // SSH port for user networking
+ Port int
+ // RemoteUsername of the vm user
+ RemoteUsername string
+}
+
+// ResourceConfig describes physical attributes of the machine
+type ResourceConfig struct {
+ // CPUs to be assigned to the VM
+ CPUs uint64
+ // Memory in megabytes assigned to the vm
+ Memory uint64
+ // Disk size in gigabytes assigned to the vm
+ DiskSize uint64
+}
+
+type MachineFile struct {
+ // Path is the fully qualified path to a file
+ Path string
+ // Symlink is a shortened version of Path by using
+ // a symlink
+ Symlink *string
+}
+
type Mount struct {
Type string
Tag string
@@ -52,7 +136,7 @@ type Mount struct {
type Monitor struct {
// Address portion of the qmp monitor (/tmp/tmp.sock)
- Address string
+ Address MachineFile
// Network portion of the qmp monitor (unix)
Network string
// Timeout in seconds for qmp monitor transactions
@@ -61,6 +145,40 @@ type Monitor struct {
var (
// defaultQMPTimeout is the timeout duration for the
- // qmp monitor interactions
+ // qmp monitor interactions.
defaultQMPTimeout time.Duration = 2 * time.Second
)
+
+// GetPath returns the working path for a machinefile. it returns
+// the symlink unless one does not exist
+func (m *MachineFile) GetPath() string {
+ if m.Symlink == nil {
+ return m.Path
+ }
+ return *m.Symlink
+}
+
+// Delete removes the machinefile symlink (if it exists) and
+// the actual path
+func (m *MachineFile) Delete() error {
+ if m.Symlink != nil {
+ if err := os.Remove(*m.Symlink); err != nil {
+ logrus.Errorf("unable to remove symlink %q", *m.Symlink)
+ }
+ }
+ return os.Remove(m.Path)
+}
+
+// NewMachineFile is a constructor for MachineFile
+func NewMachineFile(path string, symlink *string) (*MachineFile, error) {
+ if len(path) < 1 {
+ return nil, errors.New("invalid machine file path")
+ }
+ if symlink != nil && len(*symlink) < 1 {
+ return nil, errors.New("invalid symlink path")
+ }
+ return &MachineFile{
+ Path: path,
+ Symlink: symlink,
+ }, nil
+}
diff --git a/pkg/machine/qemu/config_test.go b/pkg/machine/qemu/config_test.go
new file mode 100644
index 000000000..e3e7437b5
--- /dev/null
+++ b/pkg/machine/qemu/config_test.go
@@ -0,0 +1,103 @@
+package qemu
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestMachineFile_GetPath(t *testing.T) {
+ path := "/var/tmp/podman/my.sock"
+ sym := "/tmp/podman/my.sock"
+ type fields struct {
+ Path string
+ Symlink *string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ want string
+ }{
+ {
+ name: "Original path",
+ fields: fields{path, nil},
+ want: path,
+ },
+ {
+ name: "Symlink over path",
+ fields: fields{
+ Path: path,
+ Symlink: &sym,
+ },
+ want: sym,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ m := &MachineFile{
+ Path: tt.fields.Path, //nolint: scopelint
+ Symlink: tt.fields.Symlink, //nolint: scopelint
+ }
+ if got := m.GetPath(); got != tt.want { //nolint: scopelint
+ t.Errorf("GetPath() = %v, want %v", got, tt.want) //nolint: scopelint
+ }
+ })
+ }
+}
+
+func TestNewMachineFile(t *testing.T) {
+ p := "/var/tmp/podman/my.sock"
+ sym := "/tmp/podman/my.sock"
+ empty := ""
+
+ m := MachineFile{
+ Path: p,
+ Symlink: nil,
+ }
+ type args struct {
+ path string
+ symlink *string
+ }
+ tests := []struct {
+ name string
+ args args
+ want *MachineFile
+ wantErr bool
+ }{
+ {
+ name: "Good",
+ args: args{path: p},
+ want: &m,
+ wantErr: false,
+ },
+ {
+ name: "Good with Symlink",
+ args: args{p, &sym},
+ want: &MachineFile{p, &sym},
+ wantErr: false,
+ },
+ {
+ name: "Bad path name",
+ args: args{empty, nil},
+ want: nil,
+ wantErr: true,
+ },
+ {
+ name: "Bad symlink name",
+ args: args{p, &empty},
+ want: nil,
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := NewMachineFile(tt.args.path, tt.args.symlink) //nolint: scopelint
+ if (err != nil) != tt.wantErr { //nolint: scopelint
+ t.Errorf("NewMachineFile() error = %v, wantErr %v", err, tt.wantErr) //nolint: scopelint
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) { //nolint: scopelint
+ t.Errorf("NewMachineFile() got = %v, want %v", got, tt.want) //nolint: scopelint
+ }
+ })
+ }
+}
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index d30e51215..ac8e7d75c 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -34,7 +34,7 @@ import (
var (
qemuProvider = &Provider{}
- // vmtype refers to qemu (vs libvirt, krun, etc)
+ // vmtype refers to qemu (vs libvirt, krun, etc).
vmtype = "qemu"
)
@@ -98,7 +98,7 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
return nil, err
}
- cmd := append([]string{execPath})
+ cmd := []string{execPath}
// Add memory
cmd = append(cmd, []string{"-m", strconv.Itoa(int(vm.Memory))}...)
// Add cpus
@@ -111,7 +111,7 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
return nil, err
}
vm.QMPMonitor = monitor
- cmd = append(cmd, []string{"-qmp", monitor.Network + ":/" + monitor.Address + ",server=on,wait=off"}...)
+ cmd = append(cmd, []string{"-qmp", monitor.Network + ":/" + monitor.Address.GetPath() + ",server=on,wait=off"}...)
// Add network
// Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is
@@ -134,7 +134,8 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
// LoadByName reads a json file that describes a known qemu vm
// and returns a vm instance
func (p *Provider) LoadVMByName(name string) (machine.VM, error) {
- vm := &MachineVM{UID: -1} // posix reserves -1, so use it to signify undefined
+ vm := &MachineVM{Name: name}
+ vm.HostUser = HostUser{UID: -1} // posix reserves -1, so use it to signify undefined
vmConfigDir, err := machine.GetConfDir(vmtype)
if err != nil {
return nil, err
@@ -176,7 +177,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
v.Rootful = opts.Rootful
switch opts.ImagePath {
- case "testing", "next", "stable", "":
+ case Testing, Next, Stable, "":
// Get image as usual
v.ImageStream = opts.ImagePath
dd, err := machine.NewFcosDownloader(vmtype, v.Name, opts.ImagePath)
@@ -278,7 +279,9 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
fmt.Println("An ignition path was provided. No SSH connection was added to Podman")
}
// Write the JSON file
- v.writeConfig()
+ if err := v.writeConfig(); err != nil {
+ return false, fmt.Errorf("writing JSON file: %w", err)
+ }
// User has provided ignition file so keygen
// will be skipped.
@@ -315,7 +318,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
resize.Stdout = os.Stdout
resize.Stderr = os.Stderr
if err := resize.Run(); err != nil {
- return false, errors.Errorf("error resizing image: %q", err)
+ return false, errors.Errorf("resizing image: %q", err)
}
}
// If the user provides an ignition file, we need to
@@ -370,7 +373,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
conn net.Conn
err error
qemuSocketConn net.Conn
- wait time.Duration = time.Millisecond * 500
+ wait = time.Millisecond * 500
)
if v.isIncompatible() {
@@ -428,13 +431,29 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
// Disable graphic window when not in debug mode
// Done in start, so we're not suck with the debug level we used on init
- if logrus.GetLevel() != logrus.DebugLevel {
+ if !logrus.IsLevelEnabled(logrus.DebugLevel) {
cmd = append(cmd, "-display", "none")
}
_, err = os.StartProcess(v.CmdLine[0], cmd, attr)
if err != nil {
- return err
+ // check if qemu was not found
+ if !errors.Is(err, os.ErrNotExist) {
+ return err
+ }
+ // lookup qemu again maybe the path was changed, https://github.com/containers/podman/issues/13394
+ cfg, err := config.Default()
+ if err != nil {
+ return err
+ }
+ cmd[0], err = cfg.FindHelperBinary(QemuCommand, true)
+ if err != nil {
+ return err
+ }
+ _, err = os.StartProcess(cmd[0], cmd, attr)
+ if err != nil {
+ return err
+ }
}
fmt.Println("Waiting for VM ...")
socketPath, err := getRuntimeDir()
@@ -558,12 +577,12 @@ func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.QemuMachine
func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
var disconnected bool
// check if the qmp socket is there. if not, qemu instance is gone
- if _, err := os.Stat(v.QMPMonitor.Address); os.IsNotExist(err) {
+ if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); os.IsNotExist(err) {
// Right now it is NOT an error to stop a stopped machine
logrus.Debugf("QMP monitor socket %v does not exist", v.QMPMonitor.Address)
return nil
}
- qmpMonitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address, v.QMPMonitor.Timeout)
+ qmpMonitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
if err != nil {
return err
}
@@ -626,7 +645,8 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
}
if err := qmpMonitor.Disconnect(); err != nil {
- return nil
+ // FIXME: this error should probably be returned
+ return nil // nolint: nilerr
}
disconnected = true
@@ -665,20 +685,25 @@ func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error)
if timeout == 0 {
timeout = defaultQMPTimeout
}
+ address, err := NewMachineFile(filepath.Join(rtDir, "qmp+"+name+".sock"), nil)
+ if err != nil {
+ return Monitor{}, err
+ }
monitor := Monitor{
Network: network,
- Address: filepath.Join(rtDir, "qmp_"+name+".sock"),
+ Address: *address,
Timeout: timeout,
}
return monitor, nil
}
+// Remove deletes all the files associated with a machine including ssh keys, the image itself
func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, func() error, error) {
var (
files []string
)
- // cannot remove a running vm
+ // cannot remove a running vm unless --force is used
running, err := v.isRunning()
if err != nil {
return "", nil, err
@@ -749,13 +774,14 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
func (v *MachineVM) isRunning() (bool, error) {
// Check if qmp socket path exists
- if _, err := os.Stat(v.QMPMonitor.Address); os.IsNotExist(err) {
+ if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); os.IsNotExist(err) {
return false, nil
}
// Check if we can dial it
- monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address, v.QMPMonitor.Timeout)
+ monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
if err != nil {
- return false, nil
+ // FIXME: this error should probably be returned
+ return false, nil // nolint: nilerr
}
if err := monitor.Connect(); err != nil {
return false, err
@@ -778,7 +804,7 @@ func (v *MachineVM) isRunning() (bool, error) {
func (v *MachineVM) isListening() bool {
// Check if we can dial it
- conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "localhost", v.Port), 10*time.Millisecond)
+ conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", v.Port), 10*time.Millisecond)
if err != nil {
return false
}
@@ -875,10 +901,10 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
var listed []*machine.ListResponse
- if err = filepath.Walk(vmConfigDir, func(path string, info os.FileInfo, err error) error {
+ if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
vm := new(MachineVM)
- if strings.HasSuffix(info.Name(), ".json") {
- fullPath := filepath.Join(vmConfigDir, info.Name())
+ if strings.HasSuffix(d.Name(), ".json") {
+ fullPath := filepath.Join(vmConfigDir, d.Name())
b, err := ioutil.ReadFile(fullPath)
if err != nil {
return err
@@ -1058,7 +1084,7 @@ func (v *MachineVM) isIncompatible() bool {
func (v *MachineVM) getForwardSocketPath() (string, error) {
path, err := machine.GetDataDir(v.Name)
if err != nil {
- logrus.Errorf("Error resolving data dir: %s", err.Error())
+ logrus.Errorf("Resolving data dir: %s", err.Error())
return "", nil
}
return filepath.Join(path, "podman.sock"), nil
@@ -1097,10 +1123,13 @@ func waitAndPingAPI(sock string) {
Transport: &http.Transport{
DialContext: func(context.Context, string, string) (net.Conn, error) {
con, err := net.DialTimeout("unix", sock, apiUpTimeout)
- if err == nil {
- con.SetDeadline(time.Now().Add(apiUpTimeout))
+ if err != nil {
+ return nil, err
+ }
+ if err := con.SetDeadline(time.Now().Add(apiUpTimeout)); err != nil {
+ return nil, err
}
- return con, err
+ return con, nil
},
},
}
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 5b0c757f0..5128fa313 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"net/url"
"os"
@@ -1175,10 +1176,10 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
var listed []*machine.ListResponse
- if err = filepath.Walk(vmConfigDir, func(path string, info os.FileInfo, err error) error {
+ if err = filepath.WalkDir(vmConfigDir, func(path string, d fs.DirEntry, err error) error {
vm := new(MachineVM)
- if strings.HasSuffix(info.Name(), ".json") {
- fullPath := filepath.Join(vmConfigDir, info.Name())
+ if strings.HasSuffix(d.Name(), ".json") {
+ fullPath := filepath.Join(vmConfigDir, d.Name())
b, err := ioutil.ReadFile(fullPath)
if err != nil {
return err
diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go
index a7736aee0..a264a5a0f 100644
--- a/pkg/namespaces/namespaces.go
+++ b/pkg/namespaces/namespaces.go
@@ -254,7 +254,7 @@ func (n IpcMode) IsHost() bool {
return n == hostType
}
-// IsShareable indicates whether the container's ipc namespace can be shared with another container.
+// IsShareable indicates whether the container uses its own shareable ipc namespace which can be shared.
func (n IpcMode) IsShareable() bool {
return n == shareableType
}
diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go
index 93b4e2e9f..d7143f549 100644
--- a/pkg/rootless/rootless.go
+++ b/pkg/rootless/rootless.go
@@ -1,6 +1,8 @@
package rootless
import (
+ "errors"
+ "fmt"
"os"
"sort"
"sync"
@@ -8,7 +10,6 @@ import (
"github.com/containers/storage/pkg/lockfile"
"github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
)
// TryJoinPauseProcess attempts to join the namespaces of the pause PID via
@@ -16,12 +17,15 @@ import (
// file.
func TryJoinPauseProcess(pausePidPath string) (bool, int, error) {
if _, err := os.Stat(pausePidPath); err != nil {
- return false, -1, nil
+ if errors.Is(err, os.ErrNotExist) {
+ return false, -1, nil
+ }
+ return false, -1, err
}
became, ret, err := TryJoinFromFilePaths("", false, []string{pausePidPath})
if err == nil {
- return became, ret, err
+ return became, ret, nil
}
// It could not join the pause process, let's lock the file before trying to delete it.
@@ -31,7 +35,7 @@ func TryJoinPauseProcess(pausePidPath string) (bool, int, error) {
if os.IsNotExist(err) {
return false, -1, nil
}
- return false, -1, errors.Wrapf(err, "error acquiring lock on %s", pausePidPath)
+ return false, -1, fmt.Errorf("acquiring lock on %s: %w", pausePidPath, err)
}
pidFileLock.Lock()
@@ -46,7 +50,7 @@ func TryJoinPauseProcess(pausePidPath string) (bool, int, error) {
if err != nil {
// It is still failing. We can safely remove it.
os.Remove(pausePidPath)
- return false, -1, nil
+ return false, -1, nil // nolint: nilerr
}
return became, ret, err
}
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 786e28093..cff6de5a3 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -146,7 +146,7 @@ func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) err
}
if output, err := cmd.CombinedOutput(); err != nil {
- logrus.Errorf("error running `%s`: %s", strings.Join(args, " "), output)
+ logrus.Errorf("running `%s`: %s", strings.Join(args, " "), output)
return errors.Wrapf(err, "cannot setup namespace using %q", path)
}
return nil
@@ -174,7 +174,7 @@ func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
ret := C.reexec_in_user_namespace_wait(pidC, 0)
if ret < 0 {
- return false, -1, errors.New("error waiting for the re-exec process")
+ return false, -1, errors.New("waiting for the re-exec process")
}
return true, int(ret), nil
@@ -374,7 +374,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
if fileOutput != nil {
ret := C.reexec_in_user_namespace_wait(pidC, 0)
if ret < 0 {
- return false, -1, errors.New("error waiting for the re-exec process")
+ return false, -1, errors.New("waiting for the re-exec process")
}
return true, 0, nil
@@ -391,11 +391,11 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
return joinUserAndMountNS(uint(pid), "")
}
}
- return false, -1, errors.New("error setting up the process")
+ return false, -1, errors.New("setting up the process")
}
if b[0] != '0' {
- return false, -1, errors.New("error setting up the process")
+ return false, -1, errors.New("setting up the process")
}
signals := []os.Signal{}
@@ -425,7 +425,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
ret := C.reexec_in_user_namespace_wait(pidC, 0)
if ret < 0 {
- return false, -1, errors.New("error waiting for the re-exec process")
+ return false, -1, errors.New("waiting for the re-exec process")
}
return true, int(ret), nil
diff --git a/pkg/signal/signal_common.go b/pkg/signal/signal_common.go
index 8ff4b4dbf..5ea67843a 100644
--- a/pkg/signal/signal_common.go
+++ b/pkg/signal/signal_common.go
@@ -25,7 +25,7 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) {
}
// ParseSignalNameOrNumber translates a string to a valid syscall signal. Input
-// can be a name or number representation i.e. "KILL" "9"
+// can be a name or number representation i.e. "KILL" "9".
func ParseSignalNameOrNumber(rawSignal string) (syscall.Signal, error) {
basename := strings.TrimPrefix(rawSignal, "-")
s, err := ParseSignal(basename)
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index a279b8a62..e71eafb75 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -76,8 +76,8 @@ func (s *SpecGenerator) Validate() error {
s.ContainerStorageConfig.ImageVolumeMode, strings.Join(ImageVolumeModeValues, ","))
}
// shmsize conflicts with IPC namespace
- if s.ContainerStorageConfig.ShmSize != nil && !s.ContainerStorageConfig.IpcNS.IsPrivate() {
- return errors.New("cannot set shmsize when running in the host IPC Namespace")
+ if s.ContainerStorageConfig.ShmSize != nil && (s.ContainerStorageConfig.IpcNS.IsHost() || s.ContainerStorageConfig.IpcNS.IsNone()) {
+ return errors.Errorf("cannot set shmsize when running in the %s IPC Namespace", s.ContainerStorageConfig.IpcNS)
}
//
@@ -166,7 +166,7 @@ func (s *SpecGenerator) Validate() error {
if err := s.UtsNS.validate(); err != nil {
return err
}
- if err := s.IpcNS.validate(); err != nil {
+ if err := validateIPCNS(&s.IpcNS); err != nil {
return err
}
if err := s.PidNS.validate(); err != nil {
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index a5772bc6a..8f83fc09b 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -2,6 +2,7 @@ package generate
import (
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path"
@@ -101,8 +102,8 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error {
}
// 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 {
+ if err := filepath.WalkDir(resolvedDevicePath, func(dpath string, d fs.DirEntry, e error) error {
+ if d.Type()&os.ModeDevice == os.ModeDevice {
found = true
device := fmt.Sprintf("%s:%s", dpath, filepath.Join(dest, strings.TrimPrefix(dpath, src)))
if devmode != "" {
@@ -262,8 +263,8 @@ func addDevice(g *generate.Generator, device string) error {
// ParseDevice parses device mapping string to a src, dest & permissions string
func ParseDevice(device string) (string, string, string, error) { //nolint
- src := ""
- dst := ""
+ var src string
+ var dst string
permissions := "rwm"
arr := strings.Split(device, ":")
switch len(arr) {
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 64669f34d..118d80e2c 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -337,9 +337,9 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error {
return nil
}
-// ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an exisiting container
-func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID string) (*libpod.Container, error) {
- c, err := rt.LookupContainer(contaierID)
+// ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an existing container
+func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, containerID string) (*libpod.Container, error) {
+ c, err := rt.LookupContainer(containerID)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go
index d57cb5685..987f11569 100644
--- a/pkg/specgen/generate/kube/volume.go
+++ b/pkg/specgen/generate/kube/volume.go
@@ -76,7 +76,7 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error)
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)
+ return nil, errors.Errorf("checking HostPathSocket: path %s is not a socket", hostPath.Path)
}
case v1.HostPathDirectory:
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 3f77cbe76..9ce45aaf0 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -59,7 +59,7 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
case "pid":
return specgen.ParseNamespace(cfg.Containers.PidNS)
case "ipc":
- return specgen.ParseNamespace(cfg.Containers.IPCNS)
+ return specgen.ParseIPCNamespace(cfg.Containers.IPCNS)
case "uts":
return specgen.ParseNamespace(cfg.Containers.UTSNS)
case "user":
diff --git a/pkg/specgen/generate/ports_bench_test.go b/pkg/specgen/generate/ports_bench_test.go
index f208a34c5..f65cd2f15 100644
--- a/pkg/specgen/generate/ports_bench_test.go
+++ b/pkg/specgen/generate/ports_bench_test.go
@@ -9,7 +9,7 @@ import (
func benchmarkParsePortMapping(b *testing.B, ports []types.PortMapping) {
for n := 0; n < b.N; n++ {
- ParsePortMapping(ports, nil)
+ _, _ = ParsePortMapping(ports, nil)
}
}
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index 9c6709905..988c29832 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -146,6 +146,10 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec := g.Config
configSpec.Process.Capabilities.Ambient = []string{}
+
+ // Always unset the inheritable capabilities similarly to what the Linux kernel does
+ // They are used only when using capabilities with uid != 0.
+ configSpec.Process.Capabilities.Inheritable = []string{}
configSpec.Process.Capabilities.Bounding = caplist
user := strings.Split(s.User, ":")[0]
@@ -153,7 +157,6 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" {
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
- configSpec.Process.Capabilities.Inheritable = caplist
} else {
mergedCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
if err != nil {
@@ -175,12 +178,12 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
}
configSpec.Process.Capabilities.Effective = userCaps
configSpec.Process.Capabilities.Permitted = userCaps
- configSpec.Process.Capabilities.Inheritable = 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
+ configSpec.Process.Capabilities.Inheritable = userCaps
}
}
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index 6dcc1b7bf..f30fc4671 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -292,7 +292,7 @@ func getVolumesFrom(volumesFrom []string, runtime *libpod.Runtime) (map[string]s
// 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())
+ return nil, nil, errors.Errorf("retrieving container %s spec for volumes-from", ctr.ID())
}
for _, mnt := range spec.Mounts {
if mnt.Type != define.TypeBind {
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index e672bc65f..4412eff29 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -35,6 +35,10 @@ const (
FromPod NamespaceMode = "pod"
// Private indicates the namespace is private
Private NamespaceMode = "private"
+ // Shareable indicates the namespace is shareable
+ Shareable NamespaceMode = "shareable"
+ // None indicates the IPC namespace is created without mounting /dev/shm
+ None NamespaceMode = "none"
// NoNetwork indicates no network namespace should
// be joined. loopback should still exists.
// Only used with the network namespace, invalid otherwise.
@@ -77,6 +81,11 @@ func (n *Namespace) IsHost() bool {
return n.NSMode == Host
}
+// IsNone returns a bool if the namespace is set to none
+func (n *Namespace) IsNone() bool {
+ return n.NSMode == None
+}
+
// IsBridge returns a bool if the namespace is a Bridge
func (n *Namespace) IsBridge() bool {
return n.NSMode == Bridge
@@ -158,6 +167,17 @@ func validateNetNS(n *Namespace) error {
return nil
}
+func validateIPCNS(n *Namespace) error {
+ if n == nil {
+ return nil
+ }
+ switch n.NSMode {
+ case Shareable, None:
+ return nil
+ }
+ return n.validate()
+}
+
// Validate perform simple validation on the namespace to make sure it is not
// invalid from the get-go
func (n *Namespace) validate() error {
@@ -237,7 +257,7 @@ func ParseCgroupNamespace(ns string) (Namespace, error) {
case "private", "":
toReturn.NSMode = Private
default:
- return toReturn, errors.Errorf("unrecognized namespace mode %s passed", ns)
+ return toReturn, errors.Errorf("unrecognized cgroup namespace mode %s passed", ns)
}
} else {
toReturn.NSMode = Host
@@ -245,6 +265,21 @@ func ParseCgroupNamespace(ns string) (Namespace, error) {
return toReturn, nil
}
+// ParseIPCNamespace parses a ipc namespace specification in string
+// form.
+func ParseIPCNamespace(ns string) (Namespace, error) {
+ toReturn := Namespace{}
+ switch {
+ case ns == "shareable", ns == "":
+ toReturn.NSMode = Shareable
+ return toReturn, nil
+ case ns == "none":
+ toReturn.NSMode = None
+ return toReturn, nil
+ }
+ return ParseNamespace(ns)
+}
+
// ParseUserNamespace parses a user namespace specification in string
// form.
func ParseUserNamespace(ns string) (Namespace, error) {
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index b87da61fb..186d3862b 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -847,7 +847,8 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start
if len(cmdArr) == 0 {
return nil, errors.New("Must define a healthcheck command for all healthchecks")
}
- concat := ""
+
+ var concat string
if cmdArr[0] == "CMD" || cmdArr[0] == "none" { // this is for compat, we are already split properly for most compat cases
cmdArr = strings.Fields(inCmd)
} else if cmdArr[0] != "CMD-SHELL" { // this is for podman side of things, won't contain the keywords
@@ -975,7 +976,7 @@ func parseThrottleIOPsDevices(iopsDevices []string) (map[string]specs.LinuxThrot
}
func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) {
- secretParseError := errors.New("error parsing secret")
+ secretParseError := errors.New("parsing secret")
var mount []specgen.Secret
envs := make(map[string]string)
for _, val := range secrets {
diff --git a/pkg/systemd/dbus.go b/pkg/systemd/dbus.go
index 1b1bc8be9..44feb8308 100644
--- a/pkg/systemd/dbus.go
+++ b/pkg/systemd/dbus.go
@@ -24,7 +24,6 @@ func IsSystemdSessionValid(uid int) bool {
if rootless.IsRootless() {
conn, err = GetLogindConnection(rootless.GetRootlessUID())
- object = conn.Object(dbusDest, godbus.ObjectPath(dbusPath))
if err != nil {
//unable to fetch systemd object for logind
logrus.Debugf("systemd-logind: %s", err)
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index c01bb1baf..e11aed771 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -362,7 +362,9 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
fs.StringArrayP("env", "e", nil, "")
fs.String("sdnotify", "", "")
fs.String("restart", "", "")
- fs.Parse(remainingCmd)
+ if err := fs.Parse(remainingCmd); err != nil {
+ return "", fmt.Errorf("parsing remaining command-line arguments: %w", err)
+ }
remainingCmd = filterCommonContainerFlags(remainingCmd, fs.NArg())
// If the container is in a pod, make sure that the
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index 78ae6391b..cd1486a82 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -141,7 +141,7 @@ func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (map[str
// Error out if the pod has no infra container, which we require to be the
// main service.
if !pod.HasInfraContainer() {
- return nil, errors.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name())
+ return nil, errors.Errorf("generating systemd unit files: Pod %q has no infra container", pod.Name())
}
podInfo, err := generatePodInfo(pod, options)
@@ -160,7 +160,7 @@ func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (map[str
return nil, err
}
if len(containers) == 0 {
- return nil, errors.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name())
+ return nil, errors.Errorf("generating systemd unit files: Pod %q has no containers", pod.Name())
}
graph, err := libpod.BuildContainerGraph(containers)
if err != nil {
@@ -335,7 +335,9 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
fs.SetInterspersed(false)
fs.String("name", "", "")
fs.Bool("replace", false, "")
- fs.Parse(podCreateArgs)
+ if err := fs.Parse(podCreateArgs); err != nil {
+ return "", fmt.Errorf("parsing remaining command-line arguments: %w", err)
+ }
hasNameParam := fs.Lookup("name").Changed
hasReplaceParam, err := fs.GetBool("replace")
diff --git a/pkg/terminal/console_unix.go b/pkg/terminal/console_unix.go
index e6c0442c9..53290be24 100644
--- a/pkg/terminal/console_unix.go
+++ b/pkg/terminal/console_unix.go
@@ -3,7 +3,7 @@
package terminal
-// SetConsole for non-windows environments is a no-op
+// SetConsole for non-windows environments is a no-op.
func SetConsole() error {
return nil
}
diff --git a/pkg/util/camelcase/camelcase.go b/pkg/util/camelcase/camelcase.go
index d27ac00d6..eaf7c0178 100644
--- a/pkg/util/camelcase/camelcase.go
+++ b/pkg/util/camelcase/camelcase.go
@@ -51,10 +51,10 @@ func Split(src string) (entries []string) {
}
entries = []string{}
var runes [][]rune
- lastClass := 0
- class := 0
+ var lastClass int
// split into fields based on class of unicode character
for _, r := range src {
+ var class int
switch {
case unicode.IsLower(r):
class = 1
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 925ff9830..b89978601 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -3,6 +3,7 @@ package util
import (
"encoding/json"
"fmt"
+ "io/fs"
"math"
"os"
"os/user"
@@ -656,7 +657,7 @@ func CreateCidFile(cidfile string, id string) error {
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)
+ return errors.Errorf("opening cidfile %s", cidfile)
}
if _, err = cidFile.WriteString(id); err != nil {
logrus.Error(err)
@@ -727,7 +728,24 @@ func SocketPath() (string, error) {
func LookupUser(name string) (*user.User, error) {
// Assume UID look up first, if it fails lookup by username
if u, err := user.LookupId(name); err == nil {
- return u, err
+ return u, nil
}
return user.Lookup(name)
}
+
+// SizeOfPath determines the file usage of a given path. it was called volumeSize in v1
+// and now is made to be generic and take a path instead of a libpod volume
+func SizeOfPath(path string) (uint64, error) {
+ var size uint64
+ err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
+ if err == nil && !d.IsDir() {
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
+ size += uint64(info.Size())
+ }
+ return err
+ })
+ return size, err
+}
diff --git a/pkg/util/utils_linux.go b/pkg/util/utils_linux.go
index 1cffab19d..0b21bf3c5 100644
--- a/pkg/util/utils_linux.go
+++ b/pkg/util/utils_linux.go
@@ -2,6 +2,7 @@ package util
import (
"fmt"
+ "io/fs"
"os"
"path/filepath"
"syscall"
@@ -23,17 +24,21 @@ func GetContainerPidInformationDescriptors() ([]string, error) {
// Symlinks to nodes are ignored.
func FindDeviceNodes() (map[string]string, error) {
nodes := make(map[string]string)
- err := filepath.Walk("/dev", func(path string, info os.FileInfo, err error) error {
+ err := filepath.WalkDir("/dev", func(path string, d fs.DirEntry, err error) error {
if err != nil {
logrus.Warnf("Error descending into path %s: %v", path, err)
return filepath.SkipDir
}
// If we aren't a device node, do nothing.
- if info.Mode()&(os.ModeDevice|os.ModeCharDevice) == 0 {
+ if d.Type()&(os.ModeDevice|os.ModeCharDevice) == 0 {
return nil
}
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
// We are a device node. Get major/minor.
sysstat, ok := info.Sys().(*syscall.Stat_t)
if !ok {