/
distributionscanner.go
95 lines (84 loc) · 2.66 KB
/
distributionscanner.go
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
package rhel
import (
"context"
"errors"
"fmt"
"io/fs"
"regexp"
"runtime/trace"
"strconv"
"github.com/quay/zlog"
"github.com/quay/claircore"
"github.com/quay/claircore/indexer"
"github.com/quay/claircore/pkg/tarfs"
)
var (
_ indexer.DistributionScanner = (*DistributionScanner)(nil)
_ indexer.VersionedScanner = (*DistributionScanner)(nil)
releaseRegexp = regexp.MustCompile(`Red Hat Enterprise Linux (?:Server)?\s*(?:release)?\s*(\d+)(?:\.\d)?`)
)
// DistributionScanner implements distribution detection logic for RHEL by looking for
// an `etc/os-release` file in the layer and failing that, an `etc/redhat-release` file.
//
// The DistributionScanner can be used concurrently.
type DistributionScanner struct{}
// Name implements [indexer.VersionedScanner].
func (*DistributionScanner) Name() string { return "rhel" }
// Version implements [indexer.VersionedScanner].
func (*DistributionScanner) Version() string { return "2" }
// Kind implements [indexer.VersionedScanner].
func (*DistributionScanner) Kind() string { return "distribution" }
// Scan implements [indexer.DistributionScanner].
func (ds *DistributionScanner) Scan(ctx context.Context, l *claircore.Layer) ([]*claircore.Distribution, error) {
defer trace.StartRegion(ctx, "Scanner.Scan").End()
ctx = zlog.ContextWithValues(ctx,
"component", "rhel/DistributionScanner.Scan",
"version", ds.Version(),
"layer", l.Hash.String())
zlog.Debug(ctx).Msg("start")
defer zlog.Debug(ctx).Msg("done")
rd, err := l.Reader()
if err != nil {
return nil, fmt.Errorf("rhel: unable to create layer reader: %w", err)
}
defer rd.Close()
sys, err := tarfs.New(rd)
if err != nil {
return nil, fmt.Errorf("rhel: unable to open tarfs: %w", err)
}
d, err := findDistribution(sys)
if err != nil {
return nil, fmt.Errorf("rhel: unexpected error reading files: %w", err)
}
if d == nil {
zlog.Debug(ctx).Msg("didn't find an os-release or redhat-release file")
return nil, nil
}
return []*claircore.Distribution{d}, nil
}
func findDistribution(sys fs.FS) (*claircore.Distribution, error) {
const (
osReleasePath = `etc/os-release`
rhReleasePath = `etc/redhat-release`
)
for _, n := range []string{rhReleasePath, osReleasePath} {
b, err := fs.ReadFile(sys, n)
switch {
case errors.Is(err, nil):
case errors.Is(err, fs.ErrNotExist):
continue
default:
return nil, fmt.Errorf("rhel: unexpected error reading files: %w", err)
}
ms := releaseRegexp.FindSubmatch(b)
if ms == nil {
continue
}
num, err := strconv.ParseInt(string(ms[1]), 10, 64)
if err != nil {
return nil, fmt.Errorf("rhel: unexpected error reading files: %w", err)
}
return mkRelease(num), nil
}
return nil, nil
}