cmd/list: Filter images/containers using labels

Instead of executing 'podman ps|images' several times in a row, call
them only once and get output with all images/containers. Then, filter
out the JSON using labels and keep images/containers only with matching
labels.

This simplifies the code significantly and cuts down the execution time
of 'toolbox list'. The speed gain is noticeable:

- the system has 5 images and 10 containers

Before patch: ~1.45s
After patch:  ~0.85s
This commit is contained in:
Ondřej Míchal 2021-03-22 14:51:16 +01:00
parent 49460ebc56
commit 2369da5d31

View file

@ -51,6 +51,12 @@ var (
onlyContainers bool
onlyImages bool
}
// toolboxLabels holds labels used by containers/images that mark them as compatible with Toolbox
toolboxLabels = map[string]string{
"com.github.debarshiray.toolbox": "true",
"com.github.containers.toolbox": "true",
}
)
var listCmd = &cobra.Command{
@ -123,35 +129,22 @@ func list(cmd *cobra.Command, args []string) error {
}
func getContainers() ([]toolboxContainer, error) {
logrus.Debug("Fetching containers with label=com.github.containers.toolbox=true")
args := []string{"--all", "--filter", "label=com.github.containers.toolbox=true"}
containers_old, err := podman.GetContainers(args...)
if err != nil {
return nil, fmt.Errorf("failed to list containers with label=com.github.containers.toolbox=true: %w", err)
}
logrus.Debug("Fetching containers with label=com.github.debarshiray.toolbox=true")
args = []string{"--all", "--filter", "label=com.github.debarshiray.toolbox=true"}
containers_new, err := podman.GetContainers(args...)
if err != nil {
return nil, fmt.Errorf("failed to list containers with label=com.github.debarshiray.toolbox=true: %w", err)
}
var err error
var args []string
var containers []map[string]interface{}
if podman.CheckVersion("2.0.0") {
containers = utils.JoinJSON("Id", containers_old, containers_new)
containers = utils.SortJSON(containers, "Names", true)
} else {
containers = utils.JoinJSON("ID", containers_old, containers_new)
containers = utils.SortJSON(containers, "Names", false)
var toolboxContainers []toolboxContainer
logrus.Debug("Fetching all containers")
args = []string{"--all", "--sort", "names"}
containers, err = podman.GetContainers(args...)
if err != nil {
return nil, fmt.Errorf("failed to get containers: %w", err)
}
// This section is a temporary solution that is here to prevent a major
// redesign of the way how toolbox containers are fetched.
// Remove this in Toolbox v0.2.0
var toolboxContainers []toolboxContainer
for _, container := range containers {
var c toolboxContainer
var isToolboxContainer bool = false
containerJSON, err := json.Marshal(container)
if err != nil {
logrus.Errorf("failed to marshal container: %v", err)
@ -163,7 +156,17 @@ func getContainers() ([]toolboxContainer, error) {
logrus.Errorf("failed to unmarshal container: %v", err)
continue
}
toolboxContainers = append(toolboxContainers, c)
for label := range toolboxLabels {
if _, ok := c.Labels[label]; ok {
isToolboxContainer = true
break
}
}
if isToolboxContainer {
toolboxContainers = append(toolboxContainers, c)
}
}
return toolboxContainers, nil
@ -191,38 +194,22 @@ func listHelp(cmd *cobra.Command, args []string) {
}
func getImages() ([]toolboxImage, error) {
logrus.Debug("Fetching images with label=com.github.containers.toolbox=true")
args := []string{"--filter", "label=com.github.containers.toolbox=true"}
images_old, err := podman.GetImages(args...)
if err != nil {
return nil, errors.New("failed to list images with label=com.github.containers.toolbox=true")
}
logrus.Debug("Fetching images with label=com.github.debarshiray.toolbox=true")
args = []string{"--filter", "label=com.github.debarshiray.toolbox=true"}
images_new, err := podman.GetImages(args...)
if err != nil {
return nil, errors.New("failed to list images with com.github.debarshiray.toolbox=true")
}
var err error
var args []string
var images []map[string]interface{}
if podman.CheckVersion("2.0.0") {
images = utils.JoinJSON("Id", images_old, images_new)
images = utils.SortJSON(images, "Names", true)
} else if podman.CheckVersion("1.8.3") {
images = utils.JoinJSON("ID", images_old, images_new)
images = utils.SortJSON(images, "Names", true)
} else {
images = utils.JoinJSON("id", images_old, images_new)
images = utils.SortJSON(images, "names", true)
var toolboxImages []toolboxImage
logrus.Debug("Fetching all images")
args = []string{"--sort", "repository"}
images, err = podman.GetImages(args...)
if err != nil {
return nil, fmt.Errorf("failed to get images: %w", err)
}
// This section is a temporary solution that is here to prevent a major
// redesign of the way how toolbox images are fetched.
// Remove this in Toolbox v0.2.0
var toolboxImages []toolboxImage
for _, image := range images {
var i toolboxImage
var isToolboxImage bool = false
imageJSON, err := json.Marshal(image)
if err != nil {
logrus.Errorf("failed to marshal toolbox image: %v", err)
@ -234,7 +221,17 @@ func getImages() ([]toolboxImage, error) {
logrus.Errorf("failed to unmarshal toolbox image: %v", err)
continue
}
toolboxImages = append(toolboxImages, i)
for label := range toolboxLabels {
if _, ok := i.Labels[label]; ok {
isToolboxImage = true
break
}
}
if isToolboxImage {
toolboxImages = append(toolboxImages, i)
}
}
return toolboxImages, nil