Report the size of the image that will be downloaded from a registry
This uses 'skopeo inspect' to get the size of the image on the registry, which is usually less than the size of the image in a local containers/storage image store after download (eg., 'podman images'), because they are kept compressed on the registry. Skopeo >= 1.10.0 is needed to retrieve the sizes [1]. However, this doesn't add a hard dependency on Skopeo to accommodate size-constrained operating systems like Fedora CoreOS. If skopeo(1) is missing or too old, then the size of the image won't be shown, but everything else would continue to work as before. Some changes by Debarshi Ray. [1] Skopeo commit d9dfc44888ff71a6 https://github.com/containers/skopeo/commit/d9dfc44888ff71a6 https://github.com/containers/skopeo/issues/641 https://github.com/containers/toolbox/issues/752 Signed-off-by: Nieves Montero <nmontero@redhat.com>
This commit is contained in:
parent
2129e28fe6
commit
a1c309541f
7 changed files with 96 additions and 7 deletions
|
@ -84,10 +84,6 @@ if shellcheck.found()
|
||||||
test('shellcheck toolbox (deprecated)', shellcheck, args: [toolbox_sh])
|
test('shellcheck toolbox (deprecated)', shellcheck, args: [toolbox_sh])
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if not skopeo.found()
|
|
||||||
message('Running system tests requires Skopeo for OCI image manipulation.')
|
|
||||||
endif
|
|
||||||
|
|
||||||
install_subdir(
|
install_subdir(
|
||||||
'test',
|
'test',
|
||||||
install_dir: get_option('datadir') / meson.project_name(),
|
install_dir: get_option('datadir') / meson.project_name(),
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
chdir: '{{ zuul.project.src_dir }}'
|
chdir: '{{ zuul.project.src_dir }}'
|
||||||
|
|
||||||
- name: Check versions of crucial packages
|
- name: Check versions of crucial packages
|
||||||
command: rpm -qa ShellCheck codespell *kernel* gcc *glibc* golang shadow-utils-subid-devel podman conmon containernetworking-plugins containers-common container-selinux crun fuse-overlayfs flatpak-session-helper
|
command: rpm -qa ShellCheck codespell *kernel* gcc *glibc* golang shadow-utils-subid-devel podman conmon containernetworking-plugins containers-common container-selinux crun fuse-overlayfs flatpak-session-helper skopeo
|
||||||
|
|
||||||
- name: Show podman versions
|
- name: Show podman versions
|
||||||
command: podman version
|
command: podman version
|
||||||
|
|
|
@ -54,6 +54,14 @@
|
||||||
state: absent
|
state: absent
|
||||||
update_cache: "{{ true if zuul.attempts > 1 else false }}"
|
update_cache: "{{ true if zuul.attempts > 1 else false }}"
|
||||||
|
|
||||||
|
- name: Ensure that skopeo(1) is absent
|
||||||
|
become: yes
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- skopeo
|
||||||
|
state: absent
|
||||||
|
update_cache: "{{ true if zuul.attempts > 1 else false }}"
|
||||||
|
|
||||||
- name: Download Go modules
|
- name: Download Go modules
|
||||||
shell: |
|
shell: |
|
||||||
go mod download -x
|
go mod download -x
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
chdir: '{{ zuul.project.src_dir }}'
|
chdir: '{{ zuul.project.src_dir }}'
|
||||||
|
|
||||||
- name: Check versions of crucial packages
|
- name: Check versions of crucial packages
|
||||||
command: rpm -qa ShellCheck codespell *kernel* gcc *glibc* shadow-utils-subid-devel golang podman conmon containernetworking-plugins containers-common container-selinux crun fuse-overlayfs flatpak-session-helper
|
command: rpm -qa ShellCheck codespell *kernel* gcc *glibc* shadow-utils-subid-devel golang podman conmon containernetworking-plugins containers-common container-selinux crun fuse-overlayfs flatpak-session-helper skopeo
|
||||||
|
|
||||||
- name: Show podman versions
|
- name: Show podman versions
|
||||||
command: podman version
|
command: podman version
|
||||||
|
|
|
@ -27,7 +27,9 @@ import (
|
||||||
"github.com/briandowns/spinner"
|
"github.com/briandowns/spinner"
|
||||||
"github.com/containers/toolbox/pkg/podman"
|
"github.com/containers/toolbox/pkg/podman"
|
||||||
"github.com/containers/toolbox/pkg/shell"
|
"github.com/containers/toolbox/pkg/shell"
|
||||||
|
"github.com/containers/toolbox/pkg/skopeo"
|
||||||
"github.com/containers/toolbox/pkg/utils"
|
"github.com/containers/toolbox/pkg/utils"
|
||||||
|
"github.com/docker/go-units"
|
||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -573,6 +575,30 @@ func getFullyQualifiedImageFromRepoTags(image string) (string, error) {
|
||||||
return imageFull, nil
|
return imageFull, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getImageSizeFromRegistry(imageFull string) (string, error) {
|
||||||
|
image, err := skopeo.Inspect(imageFull)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if image.LayersData == nil {
|
||||||
|
return "", errors.New("'skopeo inspect' did not have LayersData")
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageSizeFloat float64
|
||||||
|
|
||||||
|
for _, layer := range image.LayersData {
|
||||||
|
if layerSize, err := layer.Size.Float64(); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
imageSizeFloat += layerSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imageSizeHuman := units.HumanSize(imageSizeFloat)
|
||||||
|
return imageSizeHuman, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getServiceSocket(serviceName string, unitName string) (string, error) {
|
func getServiceSocket(serviceName string, unitName string) (string, error) {
|
||||||
logrus.Debugf("Resolving path to the %s socket", serviceName)
|
logrus.Debugf("Resolving path to the %s socket", serviceName)
|
||||||
|
|
||||||
|
@ -687,7 +713,15 @@ func pullImage(image, release, authFile string) (bool, error) {
|
||||||
if promptForDownload {
|
if promptForDownload {
|
||||||
fmt.Println("Image required to create toolbox container.")
|
fmt.Println("Image required to create toolbox container.")
|
||||||
|
|
||||||
prompt := fmt.Sprintf("Download %s (500MB)? [y/N]:", imageFull)
|
var prompt string
|
||||||
|
|
||||||
|
if imageSize, err := getImageSizeFromRegistry(imageFull); err != nil {
|
||||||
|
logrus.Debugf("Getting image size failed: %s", err)
|
||||||
|
prompt = fmt.Sprintf("Download %s? [y/N]:", imageFull)
|
||||||
|
} else {
|
||||||
|
prompt = fmt.Sprintf("Download %s (%s)? [y/N]:", imageFull, imageSize)
|
||||||
|
}
|
||||||
|
|
||||||
shouldPullImage = askForConfirmation(prompt)
|
shouldPullImage = askForConfirmation(prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ sources = files(
|
||||||
'cmd/utils.go',
|
'cmd/utils.go',
|
||||||
'pkg/podman/podman.go',
|
'pkg/podman/podman.go',
|
||||||
'pkg/shell/shell.go',
|
'pkg/shell/shell.go',
|
||||||
|
'pkg/skopeo/skopeo.go',
|
||||||
'pkg/utils/libsubid-wrappers.c',
|
'pkg/utils/libsubid-wrappers.c',
|
||||||
'pkg/utils/errors.go',
|
'pkg/utils/errors.go',
|
||||||
'pkg/utils/utils.go',
|
'pkg/utils/utils.go',
|
||||||
|
|
50
src/pkg/skopeo/skopeo.go
Normal file
50
src/pkg/skopeo/skopeo.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2023 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package skopeo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/containers/toolbox/pkg/shell"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Layer struct {
|
||||||
|
Size json.Number
|
||||||
|
}
|
||||||
|
type Image struct {
|
||||||
|
LayersData []Layer
|
||||||
|
}
|
||||||
|
|
||||||
|
func Inspect(target string) (*Image, error) {
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
|
||||||
|
targetWithTransport := "docker://" + target
|
||||||
|
args := []string{"inspect", "--format", "json", targetWithTransport}
|
||||||
|
|
||||||
|
if err := shell.Run("skopeo", nil, &stdout, nil, args...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
output := stdout.Bytes()
|
||||||
|
var image Image
|
||||||
|
if err := json.Unmarshal(output, &image); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &image, nil
|
||||||
|
}
|
Loading…
Reference in a new issue