From e7b7be5734c8f97475d50f696946a8a5c99104f1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sat, 6 Nov 2021 09:15:16 -0400 Subject: [PATCH] proxy: Add an API to fetch the config upconverted to OCI While the caller could fetch this today as a blob, it'd be in either docker or oci schema. In keeping with the model of having this proxy only expose OCI, add an API which uses the c/image logic to do the conversion. This is necessary for callers to get the diffIDs, and in general to implement something like an external `skopeo copy`. Signed-off-by: Colin Walters --- cmd/skopeo/proxy.go | 57 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/cmd/skopeo/proxy.go b/cmd/skopeo/proxy.go index 74d11686..70dc1115 100644 --- a/cmd/skopeo/proxy.go +++ b/cmd/skopeo/proxy.go @@ -83,9 +83,11 @@ import ( // protocolVersion is semantic version of the protocol used by this proxy. // The first version of the protocol has major version 0.2 to signify a -// departure from the original code which used HTTP. The minor version is 1 -// instead of 0 to help exercise semver parsers. -const protocolVersion = "0.2.1" +// departure from the original code which used HTTP. +// +// 0.2.1: Initial version +// 0.2.2: Added support for fetching image configuration as OCI +const protocolVersion = "0.2.2" // maxMsgSize is the current limit on a packet size. // Note that all non-metadata (i.e. payload data) is sent over a pipe. @@ -380,6 +382,53 @@ func (h *proxyHandler) GetManifest(args []interface{}) (replyBuf, error) { return ret, nil } +// GetConfig returns a copy of the image configuration, converted to OCI format. +func (h *proxyHandler) GetConfig(args []interface{}) (replyBuf, error) { + h.lock.Lock() + defer h.lock.Unlock() + + var ret replyBuf + + if h.sysctx == nil { + return ret, fmt.Errorf("Must invoke Initialize") + } + if len(args) != 1 { + return ret, fmt.Errorf("invalid request, expecting: [imgid]") + } + imgref, err := h.parseImageFromID(args[0]) + if err != nil { + return ret, err + } + + ctx := context.TODO() + config, err := imgref.img.OCIConfig(ctx) + if err != nil { + return ret, err + } + serialized, err := json.Marshal(&config.Config) + if err != nil { + return ret, err + } + + piper, f, err := h.allocPipe() + if err != nil { + return ret, err + } + + go func() { + // Signal completion when we return + defer f.wg.Done() + _, err = io.Copy(f.w, bytes.NewReader(serialized)) + if err != nil { + f.err = err + } + }() + + ret.fd = piper + ret.pipeid = uint32(f.w.Fd()) + return ret, nil +} + // GetBlob fetches a blob, performing digest verification. func (h *proxyHandler) GetBlob(args []interface{}) (replyBuf, error) { h.lock.Lock() @@ -551,6 +600,8 @@ func (h *proxyHandler) processRequest(req request) (rb replyBuf, terminate bool, rb, err = h.CloseImage(req.Args) case "GetManifest": rb, err = h.GetManifest(req.Args) + case "GetConfig": + rb, err = h.GetConfig(req.Args) case "GetBlob": rb, err = h.GetBlob(req.Args) case "FinishPipe":