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"
)
type toolboxImage struct {
ID string
Names []string
Created string
Labels map[string]string
}
type toolboxContainer struct {
ID string
Names []string
@ -107,7 +100,7 @@ func list(cmd *cobra.Command, args []string) error {
lsImages = false
}
var images []toolboxImage
var images []podman.Image
var containers []toolboxContainer
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")
args := []string{"--sort", "repository"}
data, err := podman.GetImagesJSON(args...)
images, err := podman.GetImages(args...)
if err != nil {
logrus.Debugf("Fetching all images failed: %s", err)
return nil, errors.New("failed to get images")
}
var images []toolboxImage
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
var toolboxImages []podman.Image
for _, image := range images {
for label := range toolboxLabels {
@ -216,7 +203,7 @@ func getImages() ([]toolboxImage, error) {
return toolboxImages, nil
}
func listOutput(images []toolboxImage, containers []toolboxContainer) {
func listOutput(images []podman.Image, containers []toolboxContainer) {
if len(images) != 0 {
writer := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
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 {
var raw struct {
ID string

View file

@ -24,9 +24,17 @@ import (
"github.com/HarryMichal/go-version"
"github.com/containers/toolbox/pkg/shell"
"github.com/containers/toolbox/pkg/utils"
"github.com/sirupsen/logrus"
)
type Image struct {
ID string
Names []string
Created string
Labels map[string]string
}
var (
podmanVersion string
)
@ -35,6 +43,35 @@ var (
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.
//
// 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
}
// 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"]).
//
// 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.
func GetImagesJSON(args ...string) ([]byte, error) {
func GetImages(args ...string) ([]Image, error) {
var stdout bytes.Buffer
logLevelString := LogLevel.String()
@ -112,7 +149,12 @@ func GetImagesJSON(args ...string) ([]byte, error) {
}
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