File: image.go

package info (click to toggle)
singularity-container 4.0.3%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 21,672 kB
  • sloc: asm: 3,857; sh: 2,125; ansic: 1,677; awk: 414; makefile: 110; python: 99
file content (138 lines) | stat: -rw-r--r-- 3,332 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2023 Sylabs Inc. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0

package sif

import (
	"bytes"
	"errors"
	"fmt"

	v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/partial"
	"github.com/google/go-containerregistry/pkg/v1/types"
)

var _ v1.Image = (*image)(nil)

type image struct {
	f           *fileImage
	desc        *v1.Descriptor
	rawManifest []byte
}

// Layers returns the ordered collection of filesystem layers that comprise this image. The order
// of the list is oldest/base layer first, and most-recent/top layer last.
func (im *image) Layers() ([]v1.Layer, error) {
	m, err := im.Manifest()
	if err != nil {
		return nil, err
	}

	ls := make([]v1.Layer, len(m.Layers))
	for i, d := range m.Layers {
		l, err := im.LayerByDigest(d.Digest)
		if err != nil {
			return nil, err
		}

		ls[i] = l
	}

	return ls, nil
}

// MediaType of this image's manifest.
func (im *image) MediaType() (types.MediaType, error) {
	return im.desc.MediaType, nil
}

// Size returns the size of the manifest.
func (im *image) Size() (int64, error) {
	return im.desc.Size, nil
}

// ConfigName returns the hash of the image's config file, also known as the Image ID.
func (im *image) ConfigName() (v1.Hash, error) {
	b, err := im.RawConfigFile()
	if err != nil {
		return v1.Hash{}, err
	}

	h, _, err := v1.SHA256(bytes.NewReader(b))
	return h, err
}

// ConfigFile returns this image's config file.
func (im *image) ConfigFile() (*v1.ConfigFile, error) {
	b, err := im.RawConfigFile()
	if err != nil {
		return nil, err
	}

	return v1.ParseConfigFile(bytes.NewReader(b))
}

// RawConfigFile returns the serialized bytes of ConfigFile().
func (im *image) RawConfigFile() ([]byte, error) {
	manifest, err := im.Manifest()
	if err != nil {
		return nil, err
	}

	return im.f.Bytes(manifest.Config.Digest)
}

// Digest returns the sha256 of this image's manifest.
func (im *image) Digest() (v1.Hash, error) {
	h, _, err := v1.SHA256(bytes.NewReader(im.rawManifest))
	return h, err
}

// Manifest returns this image's Manifest object.
func (im *image) Manifest() (*v1.Manifest, error) {
	return v1.ParseManifest(bytes.NewReader(im.rawManifest))
}

// RawManifest returns the serialized bytes of Manifest().
func (im *image) RawManifest() ([]byte, error) {
	return im.rawManifest, nil
}

// Descriptor returns the original descriptor from an index manifest. See partial.Descriptor.
func (im *image) Descriptor() (*v1.Descriptor, error) {
	return im.desc, nil
}

var errLayerNotFoundInImage = errors.New("layer not found in image")

// LayerByDigest returns a Layer for interacting with a particular layer of the image, looking it
// up by "digest" (the compressed hash).
func (im *image) LayerByDigest(h v1.Hash) (v1.Layer, error) {
	manifest, err := im.Manifest()
	if err != nil {
		return nil, err
	}

	for _, desc := range manifest.Layers {
		if h == desc.Digest {
			return &Layer{
				f:    im.f,
				desc: desc,
			}, nil
		}
	}

	return nil, fmt.Errorf("%w: %v", errLayerNotFoundInImage, h)
}

// LayerByDiffID is an analog to LayerByDigest, looking up by "diff id" (the uncompressed hash).
func (im *image) LayerByDiffID(h v1.Hash) (v1.Layer, error) {
	h, err := partial.DiffIDToBlob(im, h)
	if err != nil {
		return nil, err
	}

	return im.LayerByDigest(h)
}