1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
package sources
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
imgspec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/umoci/oci/cas/dir"
"github.com/opencontainers/umoci/oci/casext"
"github.com/opencontainers/umoci/oci/layer"
"go.podman.io/image/v5/copy"
"go.podman.io/image/v5/docker/reference"
"go.podman.io/image/v5/oci/layout"
"go.podman.io/image/v5/signature"
"go.podman.io/image/v5/transports/alltransports"
"go.podman.io/image/v5/types"
)
type docker struct {
common
}
// Run downloads and unpacks a docker image.
func (s *docker) Run() error {
absRootfsDir, err := filepath.Abs(s.rootfsDir)
if err != nil {
return fmt.Errorf("Failed to get absolute path of %s: %w", s.rootfsDir, err)
}
// Get some temporary storage.
ociPath, err := os.MkdirTemp("", "incus-oci-")
if err != nil {
return err
}
defer func() { _ = os.RemoveAll(ociPath) }()
// Parse the image reference
imageRef, err := reference.ParseNormalizedNamed(s.definition.Source.URL)
if err != nil {
return fmt.Errorf("Failed to parse image reference: %w", err)
}
// Docker references with both a tag and digest are currently not supported
var imageTag string
digested, ok := imageRef.(reference.Digested)
if ok {
imageTag = digested.Digest().String()
} else {
imageTag = "latest"
tagged, ok := imageRef.(reference.NamedTagged)
if ok {
imageTag = tagged.Tag()
}
}
srcRef, err := alltransports.ParseImageName(fmt.Sprintf("docker://%s", s.definition.Source.URL))
if err != nil {
return fmt.Errorf("Failed to parse image name: %w", err)
}
dstRef, err := layout.ParseReference(fmt.Sprintf("%s:%s", ociPath, imageTag))
if err != nil {
return fmt.Errorf("Failed to parse destination reference: %w", err)
}
// Create policy context
systemCtx := &types.SystemContext{
DockerInsecureSkipTLSVerify: types.OptionalBoolFalse,
}
policy := &signature.Policy{
Default: []signature.PolicyRequirement{signature.NewPRInsecureAcceptAnything()},
}
policyCtx, err := signature.NewPolicyContext(policy)
if err != nil {
return fmt.Errorf("Failed to create policy context: %w", err)
}
defer func() { _ = policyCtx.Destroy() }()
copyOptions := ©.Options{
RemoveSignatures: true,
SourceCtx: systemCtx,
DestinationCtx: systemCtx,
}
ctx := context.TODO()
// Pull image from OCI registry
copiedManifest, err := copy.Image(ctx, policyCtx, dstRef, srcRef, copyOptions)
if err != nil {
return err
}
// Unpack OCI image
unpackOptions := &layer.UnpackOptions{KeepDirlinks: true}
engine, err := dir.Open(ociPath)
if err != nil {
return err
}
engineExt := casext.NewEngine(engine)
defer func() { _ = engine.Close() }()
var manifest imgspec.Manifest
err = json.Unmarshal(copiedManifest, &manifest)
if err != nil {
return fmt.Errorf("Failed to parse manifest: %w", err)
}
return layer.UnpackRootfs(ctx, engineExt, absRootfsDir, manifest, unpackOptions)
}
|