File: docker.go

package info (click to toggle)
distrobuilder 3.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,436 kB
  • sloc: sh: 214; makefile: 76
file content (119 lines) | stat: -rw-r--r-- 2,972 bytes parent folder | download | duplicates (2)
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 := &copy.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)
}