add remaining debian & el distro support (#99)

This commit is contained in:
Alex Goodman 2020-07-23 20:35:40 -04:00 committed by GitHub
parent 5ccd6d5f6a
commit 63ba7ae47d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 213 additions and 64 deletions

View File

@ -12,21 +12,38 @@ import (
// returns a distro or nil
type parseFunc func(string) *Distro
type parseEntry struct {
path file.Path
fn parseFunc
}
// Identify parses distro-specific files to determine distro metadata like version and release
func Identify(s scope.Scope) Distro {
distro := NewUnknownDistro()
identityFiles := map[file.Path]parseFunc{
"/etc/os-release": parseOsRelease,
// Debian and Debian-based distros have the same contents linked from this path
"/usr/lib/os-release": parseOsRelease,
"/bin/busybox": parseBusyBox,
identityFiles := []parseEntry{
{
// most distros provide a link at this location
path: "/etc/os-release",
fn: parseOsRelease,
},
{
// standard location for rhel & debian distros
path: "/usr/lib/os-release",
fn: parseOsRelease,
},
{
// check for busybox (important to check this last since other distros contain the busybox binary)
path: "/bin/busybox",
fn: parseBusyBox,
},
}
for path, fn := range identityFiles {
refs, err := s.FilesByPath(path)
identifyLoop:
for _, entry := range identityFiles {
refs, err := s.FilesByPath(entry.path)
if err != nil {
log.Errorf("unable to get path refs from %s: %s", path, err)
log.Errorf("unable to get path refs from %s: %s", entry.path, err)
break
}
@ -44,18 +61,18 @@ func Identify(s scope.Scope) Distro {
}
if err != nil {
log.Debugf("unable to get contents from %s: %s", path, err)
log.Debugf("unable to get contents from %s: %s", entry.path, err)
continue
}
if content == "" {
log.Debugf("no contents in file, skipping: %s", path)
log.Debugf("no contents in file, skipping: %s", entry.path)
continue
}
if candidateDistro := fn(content); candidateDistro != nil {
if candidateDistro := entry.fn(content); candidateDistro != nil {
distro = *candidateDistro
break
break identifyLoop
}
}
}
@ -64,7 +81,7 @@ func Identify(s scope.Scope) Distro {
}
func assemble(name, version string) *Distro {
distroType, ok := Mappings[name]
distroType, ok := IDMapping[name]
// Both distro and version must be present
if len(name) == 0 || len(version) == 0 {

View File

@ -6,45 +6,103 @@ import (
"os"
"testing"
"github.com/anchore/imgbom/internal"
"github.com/anchore/imgbom/imgbom/scope"
)
func TestIdentifyDistro(t *testing.T) {
tests := []struct {
fixture string
name string
RawVersion string
Type Type
Version string
}{
{
fixture: "test-fixtures/os/ubuntu-20.04",
name: "ubuntu",
fixture: "test-fixtures/os/alpine",
Type: Alpine,
Version: "3.11.6",
},
{
fixture: "test-fixtures/os/amazon",
Type: AmazonLinux,
Version: "2.0.0",
},
{
fixture: "test-fixtures/os/busybox",
Type: Busybox,
Version: "1.31.1",
},
{
fixture: "test-fixtures/os/centos",
Type: CentOS,
Version: "8.0.0",
},
{
fixture: "test-fixtures/os/debian",
Type: Debian,
Version: "8.0.0",
},
{
fixture: "test-fixtures/os/fedora",
Type: Fedora,
Version: "31.0.0",
},
{
fixture: "test-fixtures/os/redhat",
Type: RedHat,
Version: "7.3.0",
},
{
fixture: "test-fixtures/os/ubuntu",
Type: Ubuntu,
Version: "20.4.0",
},
{
fixture: "test-fixtures/os/empty",
name: "No OS files",
Type: UnknownDistroType,
},
{
fixture: "test-fixtures/os/unmatchable",
name: "Unmatchable distro",
Type: UnknownDistroType,
},
}
observedDistros := internal.NewStringSet()
definedDistros := internal.NewStringSet()
for _, d := range All {
definedDistros.Add(d.String())
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Run(test.fixture, func(t *testing.T) {
s, err := scope.NewScopeFromDir(test.fixture, scope.AllLayersScope)
if err != nil {
t.Fatalf("unable to produce a new scope for testing: %s", test.fixture)
}
distro := Identify(s)
if distro.Type != test.Type {
t.Errorf("expected distro doesn't match: %v != %v", distro.Type, test.Type)
d := Identify(s)
observedDistros.Add(d.String())
if d.Type != test.Type {
t.Errorf("expected distro doesn't match: %v != %v", d.Type, test.Type)
}
if d.Type == UnknownDistroType && d.Version != nil {
t.Fatalf("version should be nil for unknown distros")
} else if d.Type == UnknownDistroType && d.Version == nil {
// don't check versions for unknown distro types
return
}
if d.Version.String() != test.Version {
t.Errorf("expected distro version doesn't match: %v != %v", d.Version.String(), test.Version)
}
})
}
// ensure that test cases stay in sync with the distros that can be identified
if len(observedDistros) < len(definedDistros) {
t.Errorf("distro coverage incomplete (distro=%d, coverage=%d)", len(definedDistros), len(observedDistros))
}
}
@ -86,11 +144,10 @@ func TestParseOsRelease(t *testing.T) {
for _, test := range tests {
name := fmt.Sprintf("%s:%s", test.name, test.RawVersion)
fixture, err := os.Open(test.fixture)
defer fixture.Close()
if err != nil {
t.Fatalf("failed to open fixture: %+v", err)
t.Fatalf("could not open test fixture=%s: %+v", test.fixture, err)
}
defer fixture.Close()
b, err := ioutil.ReadAll(fixture)
if err != nil {
@ -131,11 +188,10 @@ func TestParseOsReleaseFailures(t *testing.T) {
for _, test := range tests {
name := fmt.Sprintf("%s:%s", test.name, test.fixture)
fixture, err := os.Open(test.fixture)
defer fixture.Close()
if err != nil {
t.Fatalf("failed to open fixture: %+v", err)
t.Fatalf("could not open test fixture=%s: %+v", test.fixture, err)
}
defer fixture.Close()
b, err := ioutil.ReadAll(fixture)
if err != nil {

View File

@ -0,0 +1,6 @@
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.11.6
PRETTY_NAME="Alpine Linux v3.11"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"

View File

@ -0,0 +1,9 @@
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"

View File

@ -0,0 +1 @@
junk...BusyBox v1.31.1more junk

View File

@ -0,0 +1,16 @@
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

View File

@ -0,0 +1,8 @@
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=debian
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

View File

@ -0,0 +1,21 @@
NAME=Fedora
VERSION="31 (Container Image)"
ID=fedora
VERSION_ID=31
VERSION_CODENAME=""
PLATFORM_ID="platform:f31"
PRETTY_NAME="Fedora 31 (Container Image)"
ANSI_COLOR="0;34"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:31"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f31/system-administrators-guide/"
SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=31
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=31
PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"
VARIANT="Container Image"
VARIANT_ID=container

View File

@ -0,0 +1,15 @@
NAME="Red Hat Enterprise Linux Server"
VERSION="7.3 (Maipo)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="7.3"
PRETTY_NAME="Red Hat Enterprise Linux Server 7.3 (Maipo)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:7.3:GA:server"
HOME_URL="https://www.redhat.com/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7"
REDHAT_BUGZILLA_PRODUCT_VERSION=7.3
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="7.3"

View File

@ -6,17 +6,12 @@ const (
Ubuntu
RedHat
CentOS
// Fedora
// Alpine
Fedora
Alpine
Busybox
// AmazonLinux
// OracleLinux
// ArchLinux
)
const (
// UnknownVersion is a default of 0.0.0 when it can't be parsed
UnknownVersion string = "0.0.0"
AmazonLinux
OracleLinux
//ArchLinux
)
type Type int
@ -27,12 +22,12 @@ var distroStr = []string{
"ubuntu",
"redhat",
"centos",
// "fedora",
// "alpine",
"fedora",
"alpine",
"busybox",
// "amazn",
// "oraclelinux",
// "archlinux",
"amazn",
"oraclelinux",
//"archlinux",
}
var All = []Type{
@ -40,12 +35,12 @@ var All = []Type{
Ubuntu,
RedHat,
CentOS,
// Fedora,
// Alpine,
Fedora,
Alpine,
Busybox,
// AmazonLinux,
// OracleLinux,
// ArchLinux,
AmazonLinux,
OracleLinux,
//ArchLinux,
}
func (t Type) String() string {
@ -56,16 +51,16 @@ func (t Type) String() string {
return distroStr[t]
}
// Mappings connects a distro ID like "ubuntu" to a Distro type
var Mappings = map[string]Type{
// IDMapping connects a distro ID like "ubuntu" to a Distro type
var IDMapping = map[string]Type{
"debian": Debian,
"ubuntu": Ubuntu,
"rhel": RedHat,
"centos": CentOS,
// "fedora": Fedora,
// "alpine": Alpine,
"fedora": Fedora,
"alpine": Alpine,
"busybox": Busybox,
// "amazn": AmazonLinux,
// "oraclelinux": OracleLinux,
// "archlinux": ArchLinux,
"amzn": AmazonLinux,
"ol": OracleLinux,
//"arch": ArchLinux,
}

View File

@ -29,8 +29,13 @@ func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scop
}
func IdentifyDistro(s scope.Scope) distro.Distro {
log.Info("Identifying Distro")
return distro.Identify(s)
d := distro.Identify(s)
if d.Type != distro.UnknownDistroType {
log.Infof("Identified Distro: %s", d.String())
} else {
log.Info("Could not identify distro")
}
return d
}
func CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {