mirror of
https://github.com/containers/skopeo.git
synced 2025-05-05 06:27:03 +00:00
proxy: Add GetLayerInfoPiped
I was experimenting with images with lots of layers (> 200) and this invocation was incorrectly adding the entire response into what was intended as the metadata plane. `GetManifest` and `GetConfig` (even those are relatively small) still always return their data over a pipe, same as blobs. Add a new `GetLayerInfoPiped` that does the same so we can easily get this information for images with a lot of layers. Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
parent
115f3727e8
commit
a31470d7a4
@ -93,7 +93,8 @@ import (
|
|||||||
// 0.2.4: Added OpenImageOptional
|
// 0.2.4: Added OpenImageOptional
|
||||||
// 0.2.5: Added LayerInfoJSON
|
// 0.2.5: Added LayerInfoJSON
|
||||||
// 0.2.6: Policy Verification before pulling OCI
|
// 0.2.6: Policy Verification before pulling OCI
|
||||||
const protocolVersion = "0.2.6"
|
// 0.2.7: Added GetLayerInfoPiped
|
||||||
|
const protocolVersion = "0.2.7"
|
||||||
|
|
||||||
// maxMsgSize is the current limit on a packet size.
|
// maxMsgSize is the current limit on a packet size.
|
||||||
// Note that all non-metadata (i.e. payload data) is sent over a pipe.
|
// Note that all non-metadata (i.e. payload data) is sent over a pipe.
|
||||||
@ -619,9 +620,10 @@ func (h *proxyHandler) GetBlob(args []any) (replyBuf, error) {
|
|||||||
|
|
||||||
// GetLayerInfo returns data about the layers of an image, useful for reading the layer contents.
|
// GetLayerInfo returns data about the layers of an image, useful for reading the layer contents.
|
||||||
//
|
//
|
||||||
// This needs to be called since the data returned by GetManifest() does not allow to correctly
|
// This is the same as GetLayerInfoPiped, but returns its contents inline. This is subject to
|
||||||
// calling GetBlob() for the containers-storage: transport (which doesn’t store the original compressed
|
// failure for large images (because we use SOCK_SEQPACKET which has a maximum buffer size)
|
||||||
// representations referenced in the manifest).
|
// and is hence only retained for backwards compatibility. Callers are expected to use
|
||||||
|
// the semver to know whether they can call the new API.
|
||||||
func (h *proxyHandler) GetLayerInfo(args []any) (replyBuf, error) {
|
func (h *proxyHandler) GetLayerInfo(args []any) (replyBuf, error) {
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
defer h.lock.Unlock()
|
defer h.lock.Unlock()
|
||||||
@ -667,6 +669,59 @@ func (h *proxyHandler) GetLayerInfo(args []any) (replyBuf, error) {
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLayerInfoPiped returns data about the layers of an image, useful for reading the layer contents.
|
||||||
|
//
|
||||||
|
// This needs to be called since the data returned by GetManifest() does not allow to correctly
|
||||||
|
// calling GetBlob() for the containers-storage: transport (which doesn’t store the original compressed
|
||||||
|
// representations referenced in the manifest).
|
||||||
|
func (h *proxyHandler) GetLayerInfoPiped(args []any) (replyBuf, error) {
|
||||||
|
h.lock.Lock()
|
||||||
|
defer h.lock.Unlock()
|
||||||
|
|
||||||
|
var ret replyBuf
|
||||||
|
|
||||||
|
if h.sysctx == nil {
|
||||||
|
return ret, fmt.Errorf("client error: must invoke Initialize")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) != 1 {
|
||||||
|
return ret, fmt.Errorf("found %d args, expecting (imgid)", len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
imgref, err := h.parseImageFromID(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
err = h.cacheTargetManifest(imgref)
|
||||||
|
if err != nil {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
img := imgref.cachedimg
|
||||||
|
|
||||||
|
layerInfos, err := img.LayerInfosForCopy(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if layerInfos == nil {
|
||||||
|
layerInfos = img.LayerInfos()
|
||||||
|
}
|
||||||
|
|
||||||
|
layers := make([]convertedLayerInfo, 0, len(layerInfos))
|
||||||
|
for _, layer := range layerInfos {
|
||||||
|
layers = append(layers, convertedLayerInfo{layer.Digest, layer.Size, layer.MediaType})
|
||||||
|
}
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(&layers)
|
||||||
|
if err != nil {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
return h.returnBytes(nil, serialized)
|
||||||
|
}
|
||||||
|
|
||||||
// FinishPipe waits for the worker goroutine to finish, and closes the write side of the pipe.
|
// FinishPipe waits for the worker goroutine to finish, and closes the write side of the pipe.
|
||||||
func (h *proxyHandler) FinishPipe(args []any) (replyBuf, error) {
|
func (h *proxyHandler) FinishPipe(args []any) (replyBuf, error) {
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
@ -806,6 +861,8 @@ func (h *proxyHandler) processRequest(readBytes []byte) (rb replyBuf, terminate
|
|||||||
rb, err = h.GetBlob(req.Args)
|
rb, err = h.GetBlob(req.Args)
|
||||||
case "GetLayerInfo":
|
case "GetLayerInfo":
|
||||||
rb, err = h.GetLayerInfo(req.Args)
|
rb, err = h.GetLayerInfo(req.Args)
|
||||||
|
case "GetLayerInfoPiped":
|
||||||
|
rb, err = h.GetLayerInfoPiped(req.Args)
|
||||||
case "FinishPipe":
|
case "FinishPipe":
|
||||||
rb, err = h.FinishPipe(req.Args)
|
rb, err = h.FinishPipe(req.Args)
|
||||||
case "Shutdown":
|
case "Shutdown":
|
||||||
|
@ -229,7 +229,8 @@ type byteFetch struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestGetManifestAndConfig(p *proxy, img string) error {
|
// This exercises all the metadata fetching APIs.
|
||||||
|
func runTestMetadataAPIs(p *proxy, img string) error {
|
||||||
v, err := p.callNoFd("OpenImage", []any{img})
|
v, err := p.callNoFd("OpenImage", []any{img})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -291,6 +292,19 @@ func runTestGetManifestAndConfig(p *proxy, img string) error {
|
|||||||
return fmt.Errorf("No CMD or ENTRYPOINT set")
|
return fmt.Errorf("No CMD or ENTRYPOINT set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, layerInfoBytes, err := p.callReadAllBytes("GetLayerInfoPiped", []any{imgid})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var layerInfoBytesData []interface{}
|
||||||
|
err = json.Unmarshal(layerInfoBytes, &layerInfoBytesData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(layerInfoBytesData) == 0 {
|
||||||
|
return fmt.Errorf("expected layer info data")
|
||||||
|
}
|
||||||
|
|
||||||
// Also test this legacy interface
|
// Also test this legacy interface
|
||||||
_, ctrconfigBytes, err := p.callReadAllBytes("GetConfig", []any{imgid})
|
_, ctrconfigBytes, err := p.callReadAllBytes("GetConfig", []any{imgid})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -337,13 +351,13 @@ func (s *proxySuite) TestProxy() {
|
|||||||
p, err := newProxy()
|
p, err := newProxy()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = runTestGetManifestAndConfig(p, knownNotManifestListedImageX8664)
|
err = runTestMetadataAPIs(p, knownNotManifestListedImageX8664)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Testing image %s: %v", knownNotManifestListedImageX8664, err)
|
err = fmt.Errorf("Testing image %s: %v", knownNotManifestListedImageX8664, err)
|
||||||
}
|
}
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = runTestGetManifestAndConfig(p, knownListImage)
|
err = runTestMetadataAPIs(p, knownListImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Testing image %s: %v", knownListImage, err)
|
err = fmt.Errorf("Testing image %s: %v", knownListImage, err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user