cmd/list, pkg/podman: Limit access to the raw 'podman images' JSON

This builds on top of commit 0465d78fd9034ce9.

The toolboxImage type has been renamed to Image and moved into the
podman package.

There is nothing Toolbx specific about the type - it represents any
image returned by 'podman images'.  The images are only later filtered
for Toolbx images.

Secondly, having the Image type inside the podman package makes it
possible to encapsulate the unmarshalling of the JSON within the package
without exposing the raw JSON to outside consumers.  This is desirable
because the unmarshalling involves tracking changes in the JSON output
by different Podman versions, and it's better to limit such details to
the podman package.

https://github.com/containers/toolbox/pull/1190
This commit is contained in:
Debarshi Ray 2022-12-06 13:20:42 +01:00
parent 5baf3162a9
commit 5f324d537e
2 changed files with 51 additions and 51 deletions

View File

@ -30,13 +30,6 @@ import (
"golang.org/x/term" "golang.org/x/term"
) )
type toolboxImage struct {
ID string
Names []string
Created string
Labels map[string]string
}
type toolboxContainer struct { type toolboxContainer struct {
ID string ID string
Names []string Names []string
@ -107,7 +100,7 @@ func list(cmd *cobra.Command, args []string) error {
lsImages = false lsImages = false
} }
var images []toolboxImage var images []podman.Image
var containers []toolboxContainer var containers []toolboxContainer
var err error var err error
@ -187,22 +180,16 @@ func listHelp(cmd *cobra.Command, args []string) {
} }
} }
func getImages() ([]toolboxImage, error) { func getImages() ([]podman.Image, error) {
logrus.Debug("Fetching all images") logrus.Debug("Fetching all images")
args := []string{"--sort", "repository"} args := []string{"--sort", "repository"}
data, err := podman.GetImagesJSON(args...) images, err := podman.GetImages(args...)
if err != nil { if err != nil {
logrus.Debugf("Fetching all images failed: %s", err) logrus.Debugf("Fetching all images failed: %s", err)
return nil, errors.New("failed to get images") return nil, errors.New("failed to get images")
} }
var images []toolboxImage var toolboxImages []podman.Image
if err := json.Unmarshal(data, &images); err != nil {
logrus.Debugf("Fetching all images failed: %s", err)
return nil, errors.New("failed to get images")
}
var toolboxImages []toolboxImage
for _, image := range images { for _, image := range images {
for label := range toolboxLabels { for label := range toolboxLabels {
@ -216,7 +203,7 @@ func getImages() ([]toolboxImage, error) {
return toolboxImages, nil return toolboxImages, nil
} }
func listOutput(images []toolboxImage, containers []toolboxContainer) { func listOutput(images []podman.Image, containers []toolboxContainer) {
if len(images) != 0 { if len(images) != 0 {
writer := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) writer := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(writer, "%s\t%s\t%s\n", "IMAGE ID", "IMAGE NAME", "CREATED") fmt.Fprintf(writer, "%s\t%s\t%s\n", "IMAGE ID", "IMAGE NAME", "CREATED")
@ -302,35 +289,6 @@ func listOutput(images []toolboxImage, containers []toolboxContainer) {
} }
} }
func (image *toolboxImage) UnmarshalJSON(data []byte) error {
var raw struct {
ID string
Names []string
Created interface{}
Labels map[string]string
}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
image.ID = raw.ID
image.Names = raw.Names
// Until Podman 2.0.x the field 'Created' held a human-readable string in
// format "5 minutes ago". Since Podman 2.1 the field holds an integer with
// Unix time. Go interprets numbers in JSON as float64.
switch value := raw.Created.(type) {
case string:
image.Created = value
case float64:
image.Created = utils.HumanDuration(int64(value))
}
image.Labels = raw.Labels
return nil
}
func (c *toolboxContainer) UnmarshalJSON(data []byte) error { func (c *toolboxContainer) UnmarshalJSON(data []byte) error {
var raw struct { var raw struct {
ID string ID string

View File

@ -24,9 +24,17 @@ import (
"github.com/HarryMichal/go-version" "github.com/HarryMichal/go-version"
"github.com/containers/toolbox/pkg/shell" "github.com/containers/toolbox/pkg/shell"
"github.com/containers/toolbox/pkg/utils"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type Image struct {
ID string
Names []string
Created string
Labels map[string]string
}
var ( var (
podmanVersion string podmanVersion string
) )
@ -35,6 +43,35 @@ var (
LogLevel = logrus.ErrorLevel LogLevel = logrus.ErrorLevel
) )
func (image *Image) UnmarshalJSON(data []byte) error {
var raw struct {
ID string
Names []string
Created interface{}
Labels map[string]string
}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
image.ID = raw.ID
image.Names = raw.Names
// Until Podman 2.0.x the field 'Created' held a human-readable string in
// format "5 minutes ago". Since Podman 2.1 the field holds an integer with
// Unix time. Go interprets numbers in JSON as float64.
switch value := raw.Created.(type) {
case string:
image.Created = value
case float64:
image.Created = utils.HumanDuration(int64(value))
}
image.Labels = raw.Labels
return nil
}
// CheckVersion compares provided version with the version of Podman. // CheckVersion compares provided version with the version of Podman.
// //
// Takes in one string parameter that should be in the format that is used for versioning (eg. 1.0.0, 2.5.1-dev). // Takes in one string parameter that should be in the format that is used for versioning (eg. 1.0.0, 2.5.1-dev).
@ -95,14 +132,14 @@ func GetContainers(args ...string) ([]map[string]interface{}, error) {
return containers, nil return containers, nil
} }
// GetImagesJSON is a wrapper function around `podman images --format json` command. // GetImages is a wrapper function around `podman images --format json` command.
// //
// Parameter args accepts an array of strings to be passed to the wrapped command (eg. ["-a", "--filter", "123"]). // Parameter args accepts an array of strings to be passed to the wrapped command (eg. ["-a", "--filter", "123"]).
// //
// Returned value is the JSON representing the images. // Returned value is a slice of Images.
// //
// If a problem happens during execution, first argument is nil and second argument holds the error message. // If a problem happens during execution, first argument is nil and second argument holds the error message.
func GetImagesJSON(args ...string) ([]byte, error) { func GetImages(args ...string) ([]Image, error) {
var stdout bytes.Buffer var stdout bytes.Buffer
logLevelString := LogLevel.String() logLevelString := LogLevel.String()
@ -112,7 +149,12 @@ func GetImagesJSON(args ...string) ([]byte, error) {
} }
data := stdout.Bytes() data := stdout.Bytes()
return data, nil var images []Image
if err := json.Unmarshal(data, &images); err != nil {
return nil, err
}
return images, nil
} }
// GetVersion returns version of Podman in a string // GetVersion returns version of Podman in a string