summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml11
-rw-r--r--.golangci.yml55
-rwxr-xr-xAPI.md2
-rw-r--r--cmd/podman/build.go2
-rw-r--r--cmd/podman/cp.go7
-rw-r--r--cmd/podman/diff.go2
-rw-r--r--cmd/podman/history.go13
-rw-r--r--cmd/podman/imagefilters/filters.go10
-rw-r--r--cmd/podman/images.go50
-rw-r--r--cmd/podman/info.go2
-rw-r--r--cmd/podman/inspect.go2
-rw-r--r--cmd/podman/pod_pause.go2
-rw-r--r--cmd/podman/pod_ps.go2
-rw-r--r--cmd/podman/pod_restart.go2
-rw-r--r--cmd/podman/pod_stats.go18
-rw-r--r--cmd/podman/pod_unpause.go2
-rw-r--r--cmd/podman/remoteclientconfig/configfile.go2
-rw-r--r--cmd/podman/rmi.go4
-rw-r--r--cmd/podman/search.go2
-rw-r--r--cmd/podman/shared/create.go6
-rw-r--r--cmd/podman/stats.go2
-rw-r--r--cmd/podman/system_df.go8
-rw-r--r--cmd/podman/trust_set_show.go18
-rw-r--r--cmd/podman/varlink/io.podman.varlink3
-rw-r--r--cmd/podman/version.go2
-rw-r--r--cmd/podman/volume_ls.go2
-rw-r--r--docs/podman-images.1.md64
-rw-r--r--libpod/container.go8
-rw-r--r--libpod/container_api.go1
-rw-r--r--libpod/container_attach_linux.go6
-rw-r--r--libpod/container_internal.go3
-rw-r--r--libpod/container_internal_linux.go6
-rw-r--r--libpod/define/errors.go2
-rw-r--r--libpod/healthcheck.go2
-rw-r--r--libpod/image/image.go24
-rw-r--r--libpod/image/prune.go2
-rw-r--r--libpod/image/pull.go10
-rw-r--r--libpod/image/search.go3
-rw-r--r--libpod/kube.go1
-rw-r--r--libpod/oci.go3
-rw-r--r--libpod/oci_linux.go2
-rw-r--r--libpod/runtime_ctr.go12
-rw-r--r--libpod/runtime_pod_linux.go6
-rw-r--r--libpod/stats.go2
-rw-r--r--pkg/adapter/checkpoint_restore.go6
-rw-r--r--pkg/adapter/containers.go12
-rw-r--r--pkg/adapter/pods.go4
-rw-r--r--pkg/adapter/runtime.go18
-rw-r--r--pkg/adapter/runtime_remote.go19
-rw-r--r--pkg/adapter/sigproxy_linux.go2
-rw-r--r--pkg/adapter/terminal_linux.go2
-rw-r--r--pkg/apparmor/apparmor_linux.go16
-rw-r--r--pkg/cgroups/cgroups.go10
-rw-r--r--pkg/ctime/ctime_linux.go2
-rw-r--r--pkg/firewall/iptables.go1
-rw-r--r--pkg/hooks/exec/runtimeconfigfilter.go12
-rw-r--r--pkg/rootless/rootless_linux.go8
-rw-r--r--pkg/spec/config_linux.go2
-rw-r--r--pkg/spec/parse.go6
-rw-r--r--pkg/sysinfo/sysinfo_linux.go2
-rw-r--r--pkg/varlinkapi/images.go2
-rw-r--r--pkg/varlinkapi/virtwriter/virtwriter.go6
-rw-r--r--test/e2e/images_test.go16
63 files changed, 333 insertions, 201 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 70c3cb3da..578a3eef0 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -13,7 +13,7 @@ env:
####
#### Global variables used for all tasks
####
- # Name of the ultimate destination branch for this build
+ # Name of the ultimate destination branch for this CI run, PR or post-merge.
DEST_BRANCH: "master"
# Overrides default location (/tmp/cirrus) for repo clone
GOPATH: "/var/tmp/go"
@@ -194,7 +194,6 @@ build_each_commit_task:
- "vendor"
- "varlink_api"
- # $CIRRUS_BASE_BRANCH is only set when testing a PR
only_if: $CIRRUS_BRANCH != $DEST_BRANCH &&
$CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
@@ -210,9 +209,10 @@ build_each_commit_task:
setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}'
build_each_commit_script:
- - 'source $SCRIPT_BASE/lib.sh'
- - 'git fetch --depth $CIRRUS_CLONE_DEPTH origin $CIRRUS_BASE_BRANCH |& ${TIMESTAMP}'
- - 'make build-all-new-commits GIT_BASE_BRANCH=origin/$CIRRUS_BASE_BRANCH |& ${TIMESTAMP}'
+ # set -x by default, no need to spew contents of lib.sh
+ - 'source $SCRIPT_BASE/lib.sh &> /dev/null'
+ - 'git fetch --depth $CIRRUS_CLONE_DEPTH origin $DEST_BRANCH |& ${TIMESTAMP}'
+ - 'make build-all-new-commits GIT_BASE_BRANCH=origin/$DEST_BRANCH |& ${TIMESTAMP}'
on_failure:
failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh'
@@ -225,7 +225,6 @@ build_without_cgo_task:
- "vendor"
- "varlink_api"
- # $CIRRUS_BASE_BRANCH is only set when testing a PR
only_if: $CIRRUS_BRANCH != $DEST_BRANCH &&
$CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*'
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 000000000..9fcf08a43
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,55 @@
+---
+run:
+ build-tags:
+ - apparmor
+ - ostree
+ - seccomp
+ - selinux
+ concurrency: 6
+ deadline: 5m
+ skip-dirs:
+ - dependencies/*
+ - contrib
+ - test/e2e
+ - docs
+ - test/
+ - tracing
+ skip-files:
+ - iopodman.go
+linters:
+ disable-all: true
+ enable:
+ - bodyclose
+ - deadcode
+ - depguard
+ # dupl really overdid it; disabling
+ # - dupl
+ - errcheck
+ - gofmt
+ - gosimple
+ - govet
+ - ineffassign
+ - nakedret
+ - staticcheck
+ - structcheck
+ - typecheck
+ - unused
+ - varcheck
+ # - gochecknoglobals
+ # - gochecknoinits
+ # - goconst
+ # - gocritic
+ # - gocyclo
+ # - goimports
+ # - golint
+ # - gosec
+ - interfacer
+ # - lll
+ # - maligned
+ # - misspell
+ # - prealloc
+ - scopelint
+ - stylecheck
+ - unconvert
+ # I think we should uncomment this one and used it
+ # - unparam
diff --git a/API.md b/API.md
index febd094df..ec8512fd4 100755
--- a/API.md
+++ b/API.md
@@ -1592,6 +1592,8 @@ labels [map[string]](#map[string])
isParent [bool](https://godoc.org/builtin#bool)
topLayer [string](https://godoc.org/builtin#string)
+
+readOnly [bool](https://godoc.org/builtin#bool)
### <a name="ImageHistory"></a>type ImageHistory
ImageHistory describes the returned structure from ImageHistory.
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index bd7269390..5ee35dea0 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -313,7 +313,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
// the urfavecli Tail method for args
func Tail(a []string) []string {
if len(a) >= 2 {
- return []string(a)[1:]
+ return a[1:]
}
return []string{}
}
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index 7c28edd26..bee7d2199 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -122,7 +122,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
if errors.Cause(err) != define.ErrCtrStateInvalid {
return err
}
- } else if err == nil {
+ } else {
// Only add the defer if we actually paused
defer func() {
if err := ctr.Unpause(); err != nil {
@@ -486,10 +486,7 @@ func matchVolumePath(path, target string) bool {
for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) {
pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))]
}
- if pathStr == target {
- return true
- }
- return false
+ return pathStr == target
}
func pathWithBindMountSource(m specs.Mount, path string) (string, error) {
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 2b0c1d398..f052b510d 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -136,5 +136,5 @@ func diffCmd(c *cliconfig.DiffValues) error {
} else {
out = stdoutStruct{output: diffOutput}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index fea2219bc..a16aac8d8 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -141,11 +141,12 @@ func (h *historyTemplateParams) headerMap() map[string]string {
}
// getHistorytemplateOutput gets the modified history information to be printed in human readable format
-func getHistoryTemplateOutput(history []*image.History, opts historyOptions) (historyOutput []historyTemplateParams) {
+func getHistoryTemplateOutput(history []*image.History, opts historyOptions) []historyTemplateParams {
var (
- outputSize string
- createdTime string
- createdBy string
+ outputSize string
+ createdTime string
+ createdBy string
+ historyOutput []historyTemplateParams
)
for _, hist := range history {
imageID := hist.ID
@@ -175,7 +176,7 @@ func getHistoryTemplateOutput(history []*image.History, opts historyOptions) (hi
}
historyOutput = append(historyOutput, params)
}
- return
+ return historyOutput
}
// generateHistoryOutput generates the history based on the format given
@@ -194,5 +195,5 @@ func generateHistoryOutput(history []*image.History, opts historyOptions) error
out = formats.StdoutTemplateArray{Output: historyToGeneric(historyOutput, []*image.History{}), Template: opts.format, Fields: historyOutput[0].headerMap()}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
diff --git a/cmd/podman/imagefilters/filters.go b/cmd/podman/imagefilters/filters.go
index aa5776599..0b08314ce 100644
--- a/cmd/podman/imagefilters/filters.go
+++ b/cmd/podman/imagefilters/filters.go
@@ -46,6 +46,16 @@ func DanglingFilter(danglingImages bool) ResultFilter {
}
}
+// ReadOnlyFilter allows you to filter images based on read/only and read/write
+func ReadOnlyFilter(readOnly bool) ResultFilter {
+ return func(i *adapter.ContainerImage) bool {
+ if readOnly {
+ return i.IsReadOnly()
+ }
+ return !i.IsReadOnly()
+ }
+}
+
// LabelFilter allows you to filter by images labels key and/or value
func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
// We need to handle both label=key and label=key=value
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index f842573d9..3b32ee3dd 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -30,14 +30,16 @@ type imagesTemplateParams struct {
Created string
CreatedTime time.Time
Size string
+ ReadOnly bool
}
type imagesJSONParams struct {
- ID string `json:"id"`
- Name []string `json:"names"`
- Digest digest.Digest `json:"digest"`
- Created time.Time `json:"created"`
- Size *uint64 `json:"size"`
+ ID string `json:"id"`
+ Name []string `json:"names"`
+ Digest digest.Digest `json:"digest"`
+ Created time.Time `json:"created"`
+ Size *uint64 `json:"size"`
+ ReadOnly bool `json:"readonly"`
}
type imagesOptions struct {
@@ -49,6 +51,7 @@ type imagesOptions struct {
outputformat string
sort string
all bool
+ useReadOnly bool
}
// Type declaration and functions for sorting the images output
@@ -175,6 +178,13 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
return errors.Wrapf(err, "unable to get images")
}
+ for _, image := range images {
+ if image.IsReadOnly() {
+ opts.outputformat += "{{.ReadOnly}}\t"
+ break
+ }
+ }
+
var filteredImages []*adapter.ContainerImage
//filter the images
if len(c.Filter) > 0 || len(c.InputArgs) == 1 {
@@ -238,7 +248,8 @@ func sortImagesOutput(sortBy string, imagesOutput imagesSorted) imagesSorted {
}
// getImagesTemplateOutput returns the images information to be printed in human readable format
-func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) (imagesOutput imagesSorted) {
+func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) imagesSorted {
+ var imagesOutput imagesSorted
for _, img := range images {
// If all is false and the image doesn't have a name, check to see if the top layer of the image is a parent
// to another image's top layer. If it is, then it is an intermediate image so don't print out if the --all flag
@@ -282,6 +293,7 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma
CreatedTime: createdTime,
Created: units.HumanDuration(time.Since(createdTime)) + " ago",
Size: sizeStr,
+ ReadOnly: img.IsReadOnly(),
}
imagesOutput = append(imagesOutput, params)
if opts.quiet { // Show only one image ID when quiet
@@ -294,7 +306,7 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma
// Sort images by created time
sortImagesOutput(opts.sort, imagesOutput)
- return
+ return imagesOutput
}
// getImagesJSONOutput returns the images information in its raw form
@@ -305,11 +317,12 @@ func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage)
size = nil
}
params := imagesJSONParams{
- ID: img.ID(),
- Name: img.Names(),
- Digest: img.Digest(),
- Created: img.Created(),
- Size: size,
+ ID: img.ID(),
+ Name: img.Names(),
+ Digest: img.Digest(),
+ Created: img.Created(),
+ Size: size,
+ ReadOnly: img.IsReadOnly(),
}
imagesOutput = append(imagesOutput, params)
}
@@ -334,7 +347,7 @@ func generateImagesOutput(ctx context.Context, images []*adapter.ContainerImage,
imagesOutput := getImagesTemplateOutput(ctx, images, opts)
out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.outputformat, Fields: templateMap}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// GenImageOutputMap generates the map used for outputting the images header
@@ -351,6 +364,11 @@ func GenImageOutputMap() map[string]string {
if value == "ID" {
value = "Image" + value
}
+
+ if value == "ReadOnly" {
+ values[key] = "R/O"
+ continue
+ }
values[key] = strings.ToUpper(splitCamelCase(value))
}
return values
@@ -378,6 +396,12 @@ func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []s
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, imagefilters.CreatedAfterFilter(after.Created()))
+ case "readonly":
+ readonly, err := strconv.ParseBool(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid filter readonly=%s", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, imagefilters.ReadOnlyFilter(readonly))
case "dangling":
danglingImages, err := strconv.ParseBool(splitFilter[1])
if err != nil {
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index ed60970b6..bf6dd4a8f 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -97,7 +97,7 @@ func infoCmd(c *cliconfig.InfoValues) error {
out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// top-level "debug" info
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 12d89764c..cff221cb0 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -127,7 +127,7 @@ func inspectCmd(c *cliconfig.InspectValues) error {
out = formats.JSONStructArray{Output: inspectedObjects}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// func iterateInput iterates the images|containers the user has requested and returns the inspect data and error
diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go
index 75d179f52..45e1319ff 100644
--- a/cmd/podman/pod_pause.go
+++ b/cmd/podman/pod_pause.go
@@ -56,7 +56,7 @@ func podPauseCmd(c *cliconfig.PodPauseValues) error {
for _, p := range pauseIDs {
fmt.Println(p)
}
- if conErrors != nil && len(conErrors) > 0 {
+ if len(conErrors) > 0 {
for ctr, err := range conErrors {
if lastError != nil {
logrus.Errorf("%q", lastError)
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index fd8da53fb..bda447c57 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -561,5 +561,5 @@ func generatePodPsOutput(pods []*adapter.Pod, opts podPsOptions) error {
out = formats.StdoutTemplateArray{Output: podPsToGeneric(psOutput, []podPsJSONParams{}), Template: opts.Format, Fields: psOutput[0].podHeaderMap()}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index 0b009e6c7..cc090bd6e 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -58,7 +58,7 @@ func podRestartCmd(c *cliconfig.PodRestartValues) error {
for _, p := range restartIDs {
fmt.Println(p)
}
- if conErrors != nil && len(conErrors) > 0 {
+ if len(conErrors) > 0 {
for ctr, err := range conErrors {
if lastError != nil {
logrus.Errorf("%q", lastError)
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 7984f08ee..46cacc026 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -91,24 +91,6 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error {
if err != nil {
return errors.Wrapf(err, "unable to get a list of pods")
}
- // First we need to get an initial pass of pod/ctr stats (these are not printed)
- var podStats []*adapter.PodContainerStats
- for _, p := range pods {
- cons, err := p.AllContainersByID()
- if err != nil {
- return err
- }
- emptyStats := make(map[string]*libpod.ContainerStats)
- // Iterate the pods container ids and make blank stats for them
- for _, c := range cons {
- emptyStats[c] = &libpod.ContainerStats{}
- }
- ps := adapter.PodContainerStats{
- Pod: p,
- ContainerStats: emptyStats,
- }
- podStats = append(podStats, &ps)
- }
// Create empty container stat results for our first pass
var previousPodStats []*adapter.PodContainerStats
diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go
index 91c3bfdf8..833434c3f 100644
--- a/cmd/podman/pod_unpause.go
+++ b/cmd/podman/pod_unpause.go
@@ -57,7 +57,7 @@ func podUnpauseCmd(c *cliconfig.PodUnpauseValues) error {
for _, p := range unpauseIDs {
fmt.Println(p)
}
- if conErrors != nil && len(conErrors) > 0 {
+ if len(conErrors) > 0 {
for ctr, err := range conErrors {
if lastError != nil {
logrus.Errorf("%q", lastError)
diff --git a/cmd/podman/remoteclientconfig/configfile.go b/cmd/podman/remoteclientconfig/configfile.go
index 06e82b186..56a868733 100644
--- a/cmd/podman/remoteclientconfig/configfile.go
+++ b/cmd/podman/remoteclientconfig/configfile.go
@@ -35,6 +35,7 @@ func (r *RemoteConfig) GetDefault() (*RemoteConnection, error) {
return nil, ErrNoDefinedConnections
}
for _, v := range r.Connections {
+ v := v
if len(r.Connections) == 1 {
// if there is only one defined connection, we assume it is
// the default whether tagged as such or not
@@ -54,6 +55,7 @@ func (r *RemoteConfig) GetRemoteConnection(name string) (*RemoteConnection, erro
return nil, ErrNoDefinedConnections
}
for k, v := range r.Connections {
+ v := v
if k == name {
return &v, nil
}
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index 9229d497e..57e78c34a 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -87,7 +87,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
if removeAll {
var imagesToDelete []*adapter.ContainerImage
- imagesToDelete, err = runtime.GetImages()
+ imagesToDelete, err = runtime.GetRWImages()
if err != nil {
return errors.Wrapf(err, "unable to query local images")
}
@@ -107,7 +107,7 @@ func rmiCmd(c *cliconfig.RmiValues) error {
removeImage(i)
}
lastNumberofImages = len(imagesToDelete)
- imagesToDelete, err = runtime.GetImages()
+ imagesToDelete, err = runtime.GetRWImages()
if err != nil {
return err
}
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index be75b6e37..f4c51bff1 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -84,7 +84,7 @@ func searchCmd(c *cliconfig.SearchValues) error {
return nil
}
out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: searchHeaderMap()}
- return formats.Writer(out).Out()
+ return out.Out()
}
// searchHeaderMap returns the headers of a SearchResult.
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index b14ce431d..815e2d304 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -217,7 +217,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *l
} else {
con := strings.SplitN(opt, "=", 2)
if len(con) != 2 {
- return fmt.Errorf("Invalid --security-opt 1: %q", opt)
+ return fmt.Errorf("invalid --security-opt 1: %q", opt)
}
switch con[0] {
@@ -228,7 +228,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *l
case "seccomp":
config.SeccompProfilePath = con[1]
default:
- return fmt.Errorf("Invalid --security-opt 2: %q", opt)
+ return fmt.Errorf("invalid --security-opt 2: %q", opt)
}
}
}
@@ -841,7 +841,7 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig
if err != nil {
return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", inTimeout)
}
- if timeoutDuration < time.Duration(time.Second*1) {
+ if timeoutDuration < time.Duration(1) {
return nil, errors.New("healthcheck-timeout must be at least 1 second")
}
hc.Timeout = timeoutDuration
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index 05e30f95f..3accae1b6 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -200,7 +200,7 @@ func outputStats(stats []*libpod.ContainerStats, format string) error {
}
out = formats.StdoutTemplateArray{Output: statsToGeneric(outputStats, []statsOutputParams{}), Template: format, Fields: mapOfHeaders}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
func genStatsFormat(format string) string {
diff --git a/cmd/podman/system_df.go b/cmd/podman/system_df.go
index 5b5655dc9..6b9824a79 100644
--- a/cmd/podman/system_df.go
+++ b/cmd/podman/system_df.go
@@ -143,7 +143,7 @@ func generateSysDfOutput(systemDfDiskUsages []systemDfDiskUsage, format string)
"Reclaimable": "RECLAIMABLE",
}
out := formats.StdoutTemplateArray{Output: systemDfDiskUsageToGeneric(systemDfDiskUsages), Template: format, Fields: systemDfHeader}
- return formats.Writer(out).Out()
+ return out.Out()
}
func getDiskUsage(ctx context.Context, runtime *libpod.Runtime, metaData dfMetaData) ([]systemDfDiskUsage, error) {
@@ -557,7 +557,7 @@ func imagesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
return err
}
out := formats.StdoutTemplateArray{Output: systemDfImageVerboseDiskUsageToGeneric(imagesVerboseDiskUsage), Template: imageVerboseFormat, Fields: imageVerboseHeader}
- return formats.Writer(out).Out()
+ return out.Out()
}
func containersVerboseOutput(ctx context.Context, metaData dfMetaData) error {
@@ -579,7 +579,7 @@ func containersVerboseOutput(ctx context.Context, metaData dfMetaData) error {
return err
}
out := formats.StdoutTemplateArray{Output: systemDfContainerVerboseDiskUsageToGeneric(containersVerboseDiskUsage), Template: containerVerboseFormat, Fields: containerVerboseHeader}
- return formats.Writer(out).Out()
+ return out.Out()
}
@@ -597,7 +597,7 @@ func volumesVerboseOutput(ctx context.Context, metaData dfMetaData) error {
return err
}
out := formats.StdoutTemplateArray{Output: systemDfVolumeVerboseDiskUsageToGeneric(volumesVerboseDiskUsage), Template: volumeVerboseFormat, Fields: volumeVerboseHeader}
- return formats.Writer(out).Out()
+ return out.Out()
}
func verboseOutput(ctx context.Context, metaData dfMetaData) error {
diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go
index d6f0eabd8..7d2a5ddc3 100644
--- a/cmd/podman/trust_set_show.go
+++ b/cmd/podman/trust_set_show.go
@@ -118,7 +118,7 @@ func showTrustCmd(c *cliconfig.ShowTrustValues) error {
}
outjson = policyJSON
out := formats.JSONStruct{Output: outjson}
- return formats.Writer(out).Out()
+ return out.Out()
}
showOutputMap, err := getPolicyShowOutput(policyContentStruct, systemRegistriesDirPath)
@@ -126,7 +126,7 @@ func showTrustCmd(c *cliconfig.ShowTrustValues) error {
return errors.Wrapf(err, "could not show trust policies")
}
out := formats.StdoutTemplateArray{Output: showOutputMap, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"}
- return formats.Writer(out).Out()
+ return out.Out()
}
func setTrustCmd(c *cliconfig.SetTrustValues) error {
@@ -254,15 +254,12 @@ func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirP
policyJSON[repo]["type"] = repoval[0].Type
policyJSON[repo]["transport"] = transname
keyarr := []string{}
- uids := []string{}
for _, repoele := range repoval {
if len(repoele.KeyPath) > 0 {
keyarr = append(keyarr, repoele.KeyPath)
- uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
}
if len(repoele.KeyData) > 0 {
- keyarr = append(keyarr, string(repoele.KeyData))
- uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...)
+ keyarr = append(keyarr, repoele.KeyData)
}
}
policyJSON[repo]["keys"] = keyarr
@@ -308,16 +305,17 @@ func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistri
Repo: repo,
Trusttype: repoval[0].Type,
}
- keyarr := []string{}
+ // TODO - keyarr is not used and I don't know its intent; commenting out for now for someone to fix later
+ //keyarr := []string{}
uids := []string{}
for _, repoele := range repoval {
if len(repoele.KeyPath) > 0 {
- keyarr = append(keyarr, repoele.KeyPath)
+ //keyarr = append(keyarr, repoele.KeyPath)
uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
}
if len(repoele.KeyData) > 0 {
- keyarr = append(keyarr, string(repoele.KeyData))
- uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...)
+ //keyarr = append(keyarr, string(repoele.KeyData))
+ uids = append(uids, trust.GetGPGIdFromKeyData(repoele.KeyData)...)
}
}
tempTrustShowOutput.GPGid = strings.Join(uids, ", ")
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 0bf236b77..72b15c328 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -69,7 +69,8 @@ type Image (
containers: int,
labels: [string]string,
isParent: bool,
- topLayer: string
+ topLayer: string,
+ readOnly: bool
)
# ImageHistory describes the returned structure from ImageHistory.
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index 6a88993c1..314b2e266 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -57,7 +57,7 @@ func versionCmd(c *cliconfig.VersionValues) error {
default:
out = formats.StdoutTemplate{Output: clientVersion, Template: versionOutputFormat}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
defer w.Flush()
diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go
index 7248caf0c..eda5685cf 100644
--- a/cmd/podman/volume_ls.go
+++ b/cmd/podman/volume_ls.go
@@ -238,7 +238,7 @@ func generateVolLsOutput(volumes []*adapter.Volume, opts volumeLsOptions) error
}
out = formats.StdoutTemplateArray{Output: volLsToGeneric(lsOutput, []volumeLsJSONParams{}), Template: opts.Format, Fields: lsOutput[0].volHeaderMap()}
}
- return formats.Writer(out).Out()
+ return out.Out()
}
// generateVolumeFilterFuncs returns the true if the volume matches the filter set, otherwise it returns false.
diff --git a/docs/podman-images.1.md b/docs/podman-images.1.md
index 2a732de57..6360bf580 100644
--- a/docs/podman-images.1.md
+++ b/docs/podman-images.1.md
@@ -23,6 +23,26 @@ Show image digests
Filter output based on conditions provided
+ Filters:
+
+ **after==TIMESTRING**
+ Filter on images created after the given time.Time.
+
+ **before==TIMESTRING**
+ Filter on images created before the given time.Time.
+
+ **dangling=true|false**
+ Show dangling images. Dangling images are a file system layer that was used in a previous build of an image and is no longer referenced by any active images. They are denoted with the <none> tag, consume disk space and serve no active purpose.
+
+ **label**
+ Filter by images labels key and/or value.
+
+ **readonly=true|false**
+ Show only read only images or Read/Write images. The default is to show both. Read/Only images can be configured by modifying the "additionalimagestores" in the /etc/containers/storage.conf file.
+
+ **reference=**
+ Filter by image name, specified as regular expressions.
+
**--format**=*format*
Change the default output format. This can be of a supported type like 'json'
@@ -94,31 +114,31 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
# podman images --format json
[
{
- "id": "e3d42bcaf643097dd1bb0385658ae8cbe100a80f773555c44690d22c25d16b27",
- "names": [
- "docker.io/kubernetes/pause:latest"
- ],
- "digest": "sha256:0aecf73ff86844324847883f2e916d3f6984c5fae3c2f23e91d66f549fe7d423",
- "created": "2014-07-19T07:02:32.267701596Z",
- "size": 250665
+ "id": "e3d42bcaf643097dd1bb0385658ae8cbe100a80f773555c44690d22c25d16b27",
+ "names": [
+ "docker.io/kubernetes/pause:latest"
+ ],
+ "digest": "sha256:0aecf73ff86844324847883f2e916d3f6984c5fae3c2f23e91d66f549fe7d423",
+ "created": "2014-07-19T07:02:32.267701596Z",
+ "size": 250665
},
{
- "id": "ebb91b73692bd27890685846412ae338d13552165eacf7fcd5f139bfa9c2d6d9",
- "names": [
- "\u003cnone\u003e"
- ],
- "digest": "sha256:ba7e4091d27e8114a205003ca6a768905c3395d961624a2c78873d9526461032",
- "created": "2017-10-26T03:07:22.796184288Z",
- "size": 27170520
+ "id": "ebb91b73692bd27890685846412ae338d13552165eacf7fcd5f139bfa9c2d6d9",
+ "names": [
+ "\u003cnone\u003e"
+ ],
+ "digest": "sha256:ba7e4091d27e8114a205003ca6a768905c3395d961624a2c78873d9526461032",
+ "created": "2017-10-26T03:07:22.796184288Z",
+ "size": 27170520
},
{
- "id": "4526339ae51c3cdc97956a7a961c193c39dfc6bd9733b0d762a36c6881b5583a",
- "names": [
- "docker.io/library/ubuntu:latest"
- ],
- "digest": "sha256:193f7734ddd68e0fb24ba9af8c2b673aecb0227b026871f8e932dab45add7753",
- "created": "2017-10-10T20:59:05.10196344Z",
- "size": 126085200
+ "id": "4526339ae51c3cdc97956a7a961c193c39dfc6bd9733b0d762a36c6881b5583a",
+ "names": [
+ "docker.io/library/ubuntu:latest"
+ ],
+ "digest": "sha256:193f7734ddd68e0fb24ba9af8c2b673aecb0227b026871f8e932dab45add7753",
+ "created": "2017-10-10T20:59:05.10196344Z",
+ "size": 126085200
}
]
```
@@ -148,7 +168,7 @@ docker.io/library/alpine latest 3fd9065eaf02 5 months ago 4.41 MB
```
## SEE ALSO
-podman(1)
+podman(1), containers-storage.conf(5)
## HISTORY
March 2017, Originally compiled by Dan Walsh <dwalsh@redhat.com>
diff --git a/libpod/container.go b/libpod/container.go
index b71c0b2be..2d96b1120 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -445,7 +445,7 @@ func (c *Container) specFromState() (*spec.Spec, error) {
if err != nil {
return nil, errors.Wrapf(err, "error reading container config")
}
- if err := json.Unmarshal([]byte(content), &returnSpec); err != nil {
+ if err := json.Unmarshal(content, &returnSpec); err != nil {
return nil, errors.Wrapf(err, "error unmarshalling container config")
}
} else {
@@ -1030,7 +1030,7 @@ func (c *Container) StoppedByUser() (bool, error) {
// NamespacePath returns the path of one of the container's namespaces
// If the container is not running, an error will be returned
-func (c *Container) NamespacePath(ns LinuxNS) (string, error) {
+func (c *Container) NamespacePath(linuxNS LinuxNS) (string, error) { //nolint:interfacer
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -1043,11 +1043,11 @@ func (c *Container) NamespacePath(ns LinuxNS) (string, error) {
return "", errors.Wrapf(define.ErrCtrStopped, "cannot get namespace path unless container %s is running", c.ID())
}
- if ns == InvalidNS {
+ if linuxNS == InvalidNS {
return "", errors.Wrapf(define.ErrInvalidArg, "invalid namespace requested from container %s", c.ID())
}
- return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, ns.String()), nil
+ return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, linuxNS.String()), nil
}
// CGroupPath returns a cgroups "path" for a given container.
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 6f530f75f..50fa1759d 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -115,7 +115,6 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams,
if err := c.prepareToStart(ctx, recursive); err != nil {
return nil, err
}
-
attachChan := make(chan error)
// We need to ensure that we don't return until start() fired in attach.
diff --git a/libpod/container_attach_linux.go b/libpod/container_attach_linux.go
index 43dd7d579..837cbf916 100644
--- a/libpod/container_attach_linux.go
+++ b/libpod/container_attach_linux.go
@@ -88,7 +88,11 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi
if err != nil {
return errors.Wrapf(err, "failed to connect to container's attach socket: %v", socketPath)
}
- defer conn.Close()
+ defer func() {
+ if err := conn.Close(); err != nil {
+ logrus.Errorf("unable to close socket: %q", err)
+ }
+ }()
// If starting was requested, start the container and notify when that's
// done.
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 47b425c0a..ca27f5814 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1264,6 +1264,7 @@ func (c *Container) postDeleteHooks(ctx context.Context) (err error) {
return err
}
for i, hook := range extensionHooks {
+ hook := hook
logrus.Debugf("container %s: invoke poststop hook %d, path %s", c.ID(), i, hook.Path)
var stderr, stdout bytes.Buffer
hookErr, err := exec.Run(ctx, &hook, state, &stdout, &stderr, exec.DefaultPostKillTimeout)
@@ -1513,7 +1514,7 @@ func (c *Container) prepareCheckpointExport() (err error) {
logrus.Debugf("generating spec for container %q failed with %v", c.ID(), err)
return err
}
- if err := c.writeJSONFile(g.Spec(), "spec.dump"); err != nil {
+ if err := c.writeJSONFile(g.Config, "spec.dump"); err != nil {
return err
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 399220b9a..3dfd4c9e9 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -686,8 +686,8 @@ func (c *Container) importCheckpoint(input string) (err error) {
}
// Make sure the newly created config.json exists on disk
- g := generate.NewFromSpec(c.config.Spec)
- if err = c.saveSpec(g.Spec()); err != nil {
+ g := generate.Generator{Config: c.config.Spec}
+ if err = c.saveSpec(g.Config); err != nil {
return errors.Wrap(err, "Saving imported container specification for restore failed")
}
@@ -814,7 +814,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
// Save the OCI spec to disk
- if err := c.saveSpec(g.Spec()); err != nil {
+ if err := c.saveSpec(g.Config); err != nil {
return err
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 14643ced1..3b8313855 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -95,7 +95,7 @@ var (
// ErrOSNotSupported indicates the function is not available on the particular
// OS.
- ErrOSNotSupported = errors.New("No support for this OS yet")
+ ErrOSNotSupported = errors.New("no support for this OS yet")
// ErrOCIRuntime indicates an error from the OCI runtime
ErrOCIRuntime = errors.New("OCI runtime error")
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index 8ed2b12e1..1a19b88bb 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -230,7 +230,7 @@ func (c *Container) updateHealthCheckLog(hcl HealthCheckLog, inStartPeriod bool)
// increment failing streak
healthCheck.FailingStreak = healthCheck.FailingStreak + 1
// if failing streak > retries, then status to unhealthy
- if int(healthCheck.FailingStreak) >= c.HealthCheckConfig().Retries {
+ if healthCheck.FailingStreak >= c.HealthCheckConfig().Retries {
healthCheck.Status = HealthCheckUnhealthy
}
}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index f9879b85b..a057bc720 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -54,7 +54,6 @@ type Image struct {
inspect.ImageResult
inspectInfo *types.ImageInspectInfo
InputName string
- Local bool
//runtime *libpod.Runtime
image *storage.Image
imageruntime *Runtime
@@ -119,7 +118,6 @@ func setStore(options storage.StoreOptions) (storage.Store, error) {
func (ir *Runtime) newFromStorage(img *storage.Image) *Image {
image := Image{
InputName: img.ID,
- Local: true,
imageruntime: ir,
image: img,
}
@@ -132,7 +130,6 @@ func (ir *Runtime) newFromStorage(img *storage.Image) *Image {
func (ir *Runtime) NewFromLocal(name string) (*Image, error) {
image := Image{
InputName: name,
- Local: true,
imageruntime: ir,
}
localImage, err := image.getLocalImage()
@@ -153,13 +150,11 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
// We don't know if the image is local or not ... check local first
newImage := Image{
InputName: name,
- Local: false,
imageruntime: ir,
}
if !forcePull {
localImage, err := newImage.getLocalImage()
if err == nil {
- newImage.Local = true
newImage.image = localImage
return &newImage, nil
}
@@ -199,7 +194,6 @@ func (ir *Runtime) LoadFromArchiveReference(ctx context.Context, srcRef types.Im
for _, name := range imageNames {
newImage := Image{
InputName: name,
- Local: true,
imageruntime: ir,
}
img, err := newImage.getLocalImage()
@@ -299,6 +293,11 @@ func (i *Image) ID() string {
return i.image.ID
}
+// IsReadOnly returns whether the image ID comes from a local store
+func (i *Image) IsReadOnly() bool {
+ return i.image.ReadOnly
+}
+
// Digest returns the image's digest
func (i *Image) Digest() digest.Digest {
return i.image.Digest
@@ -439,12 +438,25 @@ func (ir *Runtime) getImage(image string) (*Image, error) {
// GetImages retrieves all images present in storage
func (ir *Runtime) GetImages() ([]*Image, error) {
+ return ir.getImages(false)
+}
+
+// GetRWImages retrieves all read/write images present in storage
+func (ir *Runtime) GetRWImages() ([]*Image, error) {
+ return ir.getImages(true)
+}
+
+// getImages retrieves all images present in storage
+func (ir *Runtime) getImages(rwOnly bool) ([]*Image, error) {
var newImages []*Image
images, err := ir.store.Images()
if err != nil {
return nil, err
}
for _, i := range images {
+ if rwOnly && i.ReadOnly {
+ continue
+ }
// iterating over these, be careful to not iterate on the literal
// pointer.
image := i
diff --git a/libpod/image/prune.go b/libpod/image/prune.go
index a4f8a0c9f..6ef5d321f 100644
--- a/libpod/image/prune.go
+++ b/libpod/image/prune.go
@@ -12,7 +12,7 @@ func (ir *Runtime) GetPruneImages(all bool) ([]*Image, error) {
var (
pruneImages []*Image
)
- allImages, err := ir.GetImages()
+ allImages, err := ir.GetRWImages()
if err != nil {
return nil, err
}
diff --git a/libpod/image/pull.go b/libpod/image/pull.go
index 2f1d1e912..78cfe3626 100644
--- a/libpod/image/pull.go
+++ b/libpod/image/pull.go
@@ -240,6 +240,12 @@ func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.Imag
return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, nil)
}
+func cleanErrorMessage(err error) string {
+ errMessage := strings.TrimPrefix(errors.Cause(err).Error(), "errors:\n")
+ errMessage = strings.Split(errMessage, "\n")[0]
+ return fmt.Sprintf(" %s\n", errMessage)
+}
+
// doPullImage is an internal helper interpreting pullGoal. Almost everyone should call one of the callers of doPullImage instead.
func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, label *string) ([]string, error) {
span, _ := opentracing.StartSpanFromContext(ctx, "doPullImage")
@@ -281,9 +287,9 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa
_, err = cp.Image(ctx, policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions)
if err != nil {
pullErrors = multierror.Append(pullErrors, err)
- logrus.Errorf("Error pulling image ref %s: %v", imageInfo.srcRef.StringWithinTransport(), err)
+ logrus.Debugf("Error pulling image ref %s: %v", imageInfo.srcRef.StringWithinTransport(), err)
if writer != nil {
- _, _ = io.WriteString(writer, "Failed\n")
+ _, _ = io.WriteString(writer, cleanErrorMessage(err))
}
} else {
if !goal.pullAllPairs {
diff --git a/libpod/image/search.go b/libpod/image/search.go
index 9984e5234..e557431c6 100644
--- a/libpod/image/search.go
+++ b/libpod/image/search.go
@@ -217,21 +217,18 @@ func ParseSearchFilter(filter []string) (*SearchFilter, error) {
return nil, errors.Wrapf(err, "incorrect value type for stars filter")
}
sFilter.Stars = stars
- break
case "is-automated":
if len(arr) == 2 && arr[1] == "false" {
sFilter.IsAutomated = types.OptionalBoolFalse
} else {
sFilter.IsAutomated = types.OptionalBoolTrue
}
- break
case "is-official":
if len(arr) == 2 && arr[1] == "false" {
sFilter.IsOfficial = types.OptionalBoolFalse
} else {
sFilter.IsOfficial = types.OptionalBoolTrue
}
- break
default:
return nil, errors.Errorf("invalid filter type %q", f)
}
diff --git a/libpod/kube.go b/libpod/kube.go
index b114cda72..084a3df4f 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -155,6 +155,7 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
// Deduplicate volumes, so if containers in the pod share a volume, it's only
// listed in the volumes section once
for _, vol := range volumes {
+ vol := vol
deDupPodVolumes[vol.Name] = &vol
}
}
diff --git a/libpod/oci.go b/libpod/oci.go
index 566cbd821..3daf9f834 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -169,7 +169,6 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
return nil, errors.Wrapf(err, "cannot get file for UDP socket")
}
files = append(files, f)
- break
case "tcp":
addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
@@ -186,13 +185,11 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
return nil, errors.Wrapf(err, "cannot get file for TCP socket")
}
files = append(files, f)
- break
case "sctp":
if !notifySCTP {
notifySCTP = true
logrus.Warnf("port reservation for SCTP is not supported")
}
- break
default:
return nil, fmt.Errorf("unknown protocol %s", i.Protocol)
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index 1182457f4..9ce836cb5 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -89,7 +89,7 @@ func makeAccessible(path string, uid, gid int) error {
continue
}
if st.Mode()&0111 != 0111 {
- if err := os.Chmod(path, os.FileMode(st.Mode()|0111)); err != nil {
+ if err := os.Chmod(path, st.Mode()|0111); err != nil {
return err
}
}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 4b3aeaa37..e57ab4634 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -432,20 +432,12 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
// from the state elsewhere
if !removePod {
if err := r.state.RemoveContainerFromPod(pod, c); err != nil {
- if cleanupErr == nil {
- cleanupErr = err
- } else {
- logrus.Errorf("removing container from pod: %v", err)
- }
+ cleanupErr = err
}
}
} else {
if err := r.state.RemoveContainer(c); err != nil {
- if cleanupErr == nil {
- cleanupErr = err
- } else {
- logrus.Errorf("removing container: %v", err)
- }
+ cleanupErr = err
}
}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index d667d3a25..f38e6e7c1 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -201,11 +201,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon")
conmonCgroup, err := cgroups.Load(conmonCgroupPath)
if err != nil && err != cgroups.ErrCgroupDeleted {
- if removalErr == nil {
- removalErr = errors.Wrapf(err, "error retrieving pod %s conmon cgroup %s", p.ID(), conmonCgroupPath)
- } else {
- logrus.Errorf("Error retrieving pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err)
- }
+ removalErr = errors.Wrapf(err, "error retrieving pod %s conmon cgroup %s", p.ID(), conmonCgroupPath)
}
// New resource limits
diff --git a/libpod/stats.go b/libpod/stats.go
index 52af824bb..8101fbbbd 100644
--- a/libpod/stats.go
+++ b/libpod/stats.go
@@ -86,7 +86,7 @@ func getMemLimit(cgroupLimit uint64) uint64 {
return cgroupLimit
}
- physicalLimit := uint64(si.Totalram)
+ physicalLimit := si.Totalram
if cgroupLimit > physicalLimit {
return physicalLimit
}
diff --git a/pkg/adapter/checkpoint_restore.go b/pkg/adapter/checkpoint_restore.go
index 533e9e3a2..1cac86d12 100644
--- a/pkg/adapter/checkpoint_restore.go
+++ b/pkg/adapter/checkpoint_restore.go
@@ -4,7 +4,6 @@ package adapter
import (
"context"
- "io"
"io/ioutil"
"os"
"path/filepath"
@@ -35,7 +34,7 @@ func crImportFromJSON(filePath string, v interface{}) error {
return errors.Wrapf(err, "Failed to read container definition %s for restore", filePath)
}
json := jsoniter.ConfigCompatibleWithStandardLibrary
- if err = json.Unmarshal([]byte(content), v); err != nil {
+ if err = json.Unmarshal(content, v); err != nil {
return errors.Wrapf(err, "Failed to unmarshal container definition %s for restore", filePath)
}
@@ -106,9 +105,8 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
ctrName := config.Name
// The code to load the images is copied from create.go
- var writer io.Writer
// In create.go this only set if '--quiet' does not exist.
- writer = os.Stderr
+ writer := os.Stderr
rtc, err := runtime.GetConfig()
if err != nil {
return nil, err
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 7e2384e18..9726b237f 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -69,7 +69,7 @@ func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
var timeout *uint
if cli.Flags().Changed("timeout") || cli.Flags().Changed("time") {
- t := uint(cli.Timeout)
+ t := cli.Timeout
timeout = &t
}
@@ -342,7 +342,7 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
// This means the command did not exist
exitCode = 127
- if strings.Index(err.Error(), "permission denied") > -1 {
+ if strings.Contains(err.Error(), "permission denied") {
exitCode = 126
}
return exitCode, err
@@ -405,7 +405,7 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
}
// This means the command did not exist
exitCode = 127
- if strings.Index(err.Error(), "permission denied") > -1 {
+ if strings.Contains(err.Error(), "permission denied") {
exitCode = 126
}
if c.IsSet("rm") {
@@ -1057,7 +1057,7 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri
}
timeout := int(ctr.StopTimeout())
if c.StopTimeout >= 0 {
- timeout = int(c.StopTimeout)
+ timeout = c.StopTimeout
}
name := ctr.ID()
if c.Name {
@@ -1153,9 +1153,7 @@ func (r *LocalRuntime) Exec(c *cliconfig.ExecValues, cmd []string) error {
for _, e := range entries {
i, err := strconv.Atoi(e.Name())
if err != nil {
- if err != nil {
- return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
- }
+ return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
}
m[i] = true
}
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 2ca4f228f..5960fac60 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -155,7 +155,7 @@ func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValue
for _, p := range pods {
stopped := true
- conErrs, stopErr := p.StopWithTimeout(ctx, true, int(timeout))
+ conErrs, stopErr := p.StopWithTimeout(ctx, true, timeout)
if stopErr != nil {
errs = append(errs, stopErr)
stopped = false
@@ -532,7 +532,6 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil {
return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path)
}
- break
case v1.HostPathFileOrCreate:
if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, createFilePermission)
@@ -547,7 +546,6 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil {
return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path)
}
- break
case v1.HostPathDirectory:
case v1.HostPathFile:
case v1.HostPathUnset:
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index e65f07898..ee6913cc0 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -85,16 +85,27 @@ func getRuntime(runtime *libpod.Runtime) (*LocalRuntime, error) {
// GetImages returns a slice of images in containerimages
func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
+ return r.getImages(false)
+}
+
+// GetRWImages returns a slice of read/write images in containerimages
+func (r *LocalRuntime) GetRWImages() ([]*ContainerImage, error) {
+ return r.getImages(true)
+}
+
+func (r *LocalRuntime) getImages(rwOnly bool) ([]*ContainerImage, error) {
var containerImages []*ContainerImage
images, err := r.Runtime.ImageRuntime().GetImages()
if err != nil {
return nil, err
}
for _, i := range images {
+ if rwOnly && i.IsReadOnly() {
+ continue
+ }
containerImages = append(containerImages, &ContainerImage{i})
}
return containerImages, nil
-
}
// NewImageFromLocal returns a containerimage representation of a image from local storage
@@ -321,10 +332,7 @@ func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfi
// IsImageNotFound checks if the error indicates that no image was found.
func IsImageNotFound(err error) bool {
- if errors.Cause(err) == image.ErrNoSuchImage {
- return true
- }
- return false
+ return errors.Cause(err) == image.ErrNoSuchImage
}
// HealthCheck is a wrapper to same named function in libpod
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index db3f23629..9fae39df0 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -129,6 +129,7 @@ type remoteImage struct {
isParent bool
Runtime *LocalRuntime
TopLayer string
+ ReadOnly bool
}
// Container ...
@@ -169,12 +170,24 @@ type remoteVolume struct {
// GetImages returns a slice of containerimages over a varlink connection
func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
+ return r.getImages(false)
+}
+
+// GetRWImages returns a slice of read/write containerimages over a varlink connection
+func (r *LocalRuntime) GetRWImages() ([]*ContainerImage, error) {
+ return r.getImages(true)
+}
+
+func (r *LocalRuntime) getImages(rwOnly bool) ([]*ContainerImage, error) {
var newImages []*ContainerImage
images, err := iopodman.ListImages().Call(r.Conn)
if err != nil {
return nil, err
}
for _, i := range images {
+ if rwOnly && i.ReadOnly {
+ continue
+ }
name := i.Id
if len(i.RepoTags) > 1 {
name = i.RepoTags[0]
@@ -207,6 +220,7 @@ func imageInListToContainerImage(i iopodman.Image, name string, runtime *LocalRu
isParent: i.IsParent,
Runtime: runtime,
TopLayer: i.TopLayer,
+ ReadOnly: i.ReadOnly,
}
return &ContainerImage{ri}, nil
}
@@ -302,6 +316,11 @@ func (ci *ContainerImage) Created() time.Time {
return ci.remoteImage.Created
}
+// IsReadOnly returns whether the image is ReadOnly
+func (ci *ContainerImage) IsReadOnly() bool {
+ return ci.remoteImage.ReadOnly
+}
+
// Size returns the size of the image
func (ci *ContainerImage) Size(ctx context.Context) (*uint64, error) {
usize := uint64(ci.remoteImage.Size)
diff --git a/pkg/adapter/sigproxy_linux.go b/pkg/adapter/sigproxy_linux.go
index efa6afa7b..ebfeab725 100644
--- a/pkg/adapter/sigproxy_linux.go
+++ b/pkg/adapter/sigproxy_linux.go
@@ -33,6 +33,4 @@ func ProxySignals(ctr *libpod.Container) {
}
}
}()
-
- return
}
diff --git a/pkg/adapter/terminal_linux.go b/pkg/adapter/terminal_linux.go
index e3255ecb6..9f6ddc2e6 100644
--- a/pkg/adapter/terminal_linux.go
+++ b/pkg/adapter/terminal_linux.go
@@ -14,6 +14,8 @@ import (
)
// 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, recursive bool) error {
resize := make(chan remotecommand.TerminalSize)
diff --git a/pkg/apparmor/apparmor_linux.go b/pkg/apparmor/apparmor_linux.go
index 479600408..33710ff56 100644
--- a/pkg/apparmor/apparmor_linux.go
+++ b/pkg/apparmor/apparmor_linux.go
@@ -92,16 +92,24 @@ func InstallDefault(name string) error {
return err
}
if err := cmd.Start(); err != nil {
- pipe.Close()
+ if pipeErr := pipe.Close(); pipeErr != nil {
+ logrus.Errorf("unable to close apparmor pipe: %q", pipeErr)
+ }
return err
}
if err := p.generateDefault(pipe); err != nil {
- pipe.Close()
- cmd.Wait()
+ if pipeErr := pipe.Close(); pipeErr != nil {
+ logrus.Errorf("unable to close apparmor pipe: %q", pipeErr)
+ }
+ if cmdErr := cmd.Wait(); cmdErr != nil {
+ logrus.Errorf("unable to wait for apparmor command: %q", cmdErr)
+ }
return err
}
- pipe.Close()
+ if pipeErr := pipe.Close(); pipeErr != nil {
+ logrus.Errorf("unable to close apparmor pipe: %q", pipeErr)
+ }
return cmd.Wait()
}
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index fda19bff8..f2c6b548e 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -155,7 +155,7 @@ func createCgroupv2Path(path string) (Err error) {
if err != nil {
return errors.Wrapf(err, "read /sys/fs/cgroup/cgroup.controllers")
}
- if !filepath.HasPrefix(path, "/sys/fs/cgroup") {
+ if !strings.HasPrefix(path, "/sys/fs/cgroup/") {
return fmt.Errorf("invalid cgroup path %s", path)
}
@@ -274,12 +274,6 @@ func readFileAsUint64(path string) (uint64, error) {
return ret, nil
}
-func (c *CgroupControl) writePidToTasks(pid int, name string) error {
- path := filepath.Join(c.getCgroupv1Path(name), "tasks")
- payload := []byte(fmt.Sprintf("%d", pid))
- return ioutil.WriteFile(path, payload, 0644)
-}
-
// New creates a new cgroup control
func New(path string, resources *spec.LinuxResources) (*CgroupControl, error) {
cgroup2, err := IsCgroup2UnifiedMode()
@@ -384,7 +378,7 @@ func rmDirRecursively(path string) error {
}
}
}
- if os.Remove(path); err != nil {
+ if err := os.Remove(path); err != nil {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "remove %s", path)
}
diff --git a/pkg/ctime/ctime_linux.go b/pkg/ctime/ctime_linux.go
index e83269d49..28ad959cf 100644
--- a/pkg/ctime/ctime_linux.go
+++ b/pkg/ctime/ctime_linux.go
@@ -10,5 +10,5 @@ import (
func created(fi os.FileInfo) time.Time {
st := fi.Sys().(*syscall.Stat_t)
- return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec))
+ return time.Unix(st.Ctim.Sec, st.Ctim.Nsec)
}
diff --git a/pkg/firewall/iptables.go b/pkg/firewall/iptables.go
index 92d249f7b..169ddc1d7 100644
--- a/pkg/firewall/iptables.go
+++ b/pkg/firewall/iptables.go
@@ -151,7 +151,6 @@ type iptablesBackend struct {
protos map[iptables.Protocol]*iptables.IPTables
privChainName string
adminChainName string
- ifName string
}
// iptablesBackend implements the FirewallBackend interface
diff --git a/pkg/hooks/exec/runtimeconfigfilter.go b/pkg/hooks/exec/runtimeconfigfilter.go
index c6971f680..10b8fedc2 100644
--- a/pkg/hooks/exec/runtimeconfigfilter.go
+++ b/pkg/hooks/exec/runtimeconfigfilter.go
@@ -27,7 +27,11 @@ var spewConfig = spew.ConfigState{
// reads back a possibly-altered form from their standard output).
func RuntimeConfigFilter(ctx context.Context, hooks []spec.Hook, config *spec.Spec, postKillTimeout time.Duration) (hookErr, err error) {
data, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
for i, hook := range hooks {
+ hook := hook
var stdout bytes.Buffer
hookErr, err = Run(ctx, &hook, data, &stdout, nil, postKillTimeout)
if err != nil {
@@ -43,11 +47,11 @@ func RuntimeConfigFilter(ctx context.Context, hooks []spec.Hook, config *spec.Sp
}
if !reflect.DeepEqual(config, &newConfig) {
- old := spewConfig.Sdump(config)
- new := spewConfig.Sdump(&newConfig)
+ oldConfig := spewConfig.Sdump(config)
+ newConfig := spewConfig.Sdump(&newConfig)
diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
- A: difflib.SplitLines(old),
- B: difflib.SplitLines(new),
+ A: difflib.SplitLines(oldConfig),
+ B: difflib.SplitLines(newConfig),
FromFile: "Old",
FromDate: "",
ToFile: "New",
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 99a0eb729..6e48988c5 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -111,10 +111,8 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
args := []string{path, fmt.Sprintf("%d", pid)}
args = appendTriplet(args, 0, hostID, 1)
- if mappings != nil {
- for _, i := range mappings {
- args = appendTriplet(args, i.ContainerID+1, i.HostID, i.Size)
- }
+ for _, i := range mappings {
+ args = appendTriplet(args, i.ContainerID+1, i.HostID, i.Size)
}
cmd := exec.Cmd{
Path: path,
@@ -442,7 +440,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
return false, -1, errors.Wrapf(err, "write to sync pipe")
}
- b := make([]byte, 1, 1)
+ b := make([]byte, 1)
_, err = w.Read(b)
if err != nil {
return false, -1, errors.Wrapf(err, "read from sync pipe")
diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go
index a84e9a72f..60d31d78e 100644
--- a/pkg/spec/config_linux.go
+++ b/pkg/spec/config_linux.go
@@ -160,7 +160,7 @@ func (c *CreateConfig) addPrivilegedDevices(g *generate.Generator) error {
}
// Add resources device - need to clear the existing one first.
- g.Spec().Linux.Resources.Devices = nil
+ g.Config.Linux.Resources.Devices = nil
g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
return nil
}
diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go
index d688b8d1b..c2572a033 100644
--- a/pkg/spec/parse.go
+++ b/pkg/spec/parse.go
@@ -126,13 +126,9 @@ func validateIOpsDevice(val string) (*throttleDevice, error) { //nolint
if err != nil {
return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
}
- if rate < 0 {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
- }
-
return &throttleDevice{
path: split[0],
- rate: uint64(rate),
+ rate: rate,
}, nil
}
diff --git a/pkg/sysinfo/sysinfo_linux.go b/pkg/sysinfo/sysinfo_linux.go
index f4047b63c..9e675c655 100644
--- a/pkg/sysinfo/sysinfo_linux.go
+++ b/pkg/sysinfo/sysinfo_linux.go
@@ -15,7 +15,7 @@ import (
func findCgroupMountpoints() (map[string]string, error) {
cgMounts, err := cgroups.GetCgroupMounts(false)
if err != nil {
- return nil, fmt.Errorf("Failed to parse cgroup information: %v", err)
+ return nil, fmt.Errorf("failed to parse cgroup information: %v", err)
}
mps := make(map[string]string)
for _, m := range cgMounts {
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 2bebfd406..739a3e582 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -69,6 +69,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
Containers: int64(len(containers)),
Labels: labels,
IsParent: isParent,
+ ReadOnly: image.IsReadOnly(),
}
imageList = append(imageList, i)
}
@@ -109,6 +110,7 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error {
Containers: int64(len(containers)),
Labels: labels,
TopLayer: newImage.TopLayer(),
+ ReadOnly: newImage.IsReadOnly(),
}
return call.ReplyGetImage(il)
}
diff --git a/pkg/varlinkapi/virtwriter/virtwriter.go b/pkg/varlinkapi/virtwriter/virtwriter.go
index e747984c7..5e88914b2 100644
--- a/pkg/varlinkapi/virtwriter/virtwriter.go
+++ b/pkg/varlinkapi/virtwriter/virtwriter.go
@@ -6,8 +6,6 @@ import (
"encoding/json"
"errors"
"io"
- "os"
-
"k8s.io/client-go/tools/remotecommand"
)
@@ -90,7 +88,7 @@ func (v VirtWriteCloser) Write(input []byte) (int, error) {
}
// Reader decodes the content that comes over the wire and directs it to the proper destination.
-func Reader(r *bufio.Reader, output, errput *os.File, input *io.PipeWriter, resize chan remotecommand.TerminalSize) error {
+func Reader(r *bufio.Reader, output io.Writer, errput io.Writer, input io.Writer, resize chan remotecommand.TerminalSize) error {
var messageSize int64
headerBytes := make([]byte, 8)
@@ -149,7 +147,7 @@ func Reader(r *bufio.Reader, output, errput *os.File, input *io.PipeWriter, resi
default:
// Something really went wrong
- return errors.New("Unknown multiplex destination")
+ return errors.New("unknown multiplex destination")
}
}
}
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index b6dae33ee..4eadc77e7 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -388,4 +388,20 @@ LABEL "com.example.vendor"="Example Vendor"
output = session.OutputToString()
Expect(output).To(Equal("[]"))
})
+
+ It("podman images --filter readonly", func() {
+ SkipIfRemote()
+ dockerfile := `FROM docker.io/library/alpine:latest
+`
+ podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
+ result := podmanTest.Podman([]string{"images", "-f", "readonly=true"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ result1 := podmanTest.Podman([]string{"images", "--filter", "readonly=false"})
+ result1.WaitWithDefaultTimeout()
+ Expect(result1.ExitCode()).To(Equal(0))
+ Expect(result.OutputToStringArray()).To(Not(Equal(result1.OutputToStringArray())))
+ })
+
})