Merge pull request #1575 from Weichen81/arm-multi-arch
Fix pull-multi-arch images for Arm
This commit is contained in:
commit
1d896a82c2
85
platforms/cpuinfo.go
Normal file
85
platforms/cpuinfo.go
Normal file
@ -0,0 +1,85 @@
|
||||
package platforms
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Present the ARM instruction set architecture, eg: v7, v8
|
||||
var cpuVariant string
|
||||
|
||||
func init() {
|
||||
if isArmArch(runtime.GOARCH) {
|
||||
cpuVariant = getCPUVariant()
|
||||
} else {
|
||||
cpuVariant = ""
|
||||
}
|
||||
}
|
||||
|
||||
// For Linux, the kernel has already detected the ABI, ISA and Features.
|
||||
// So we don't need to access the ARM registers to detect platform information
|
||||
// by ourselves. We can just parse these information from /proc/cpuinfo
|
||||
func getCPUInfo(pattern string) (info string, err error) {
|
||||
if !isLinuxOS(runtime.GOOS) {
|
||||
return "", errors.Wrapf(errdefs.ErrNotImplemented, "getCPUInfo for OS %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
cpuinfo, err := os.Open("/proc/cpuinfo")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cpuinfo.Close()
|
||||
|
||||
// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
|
||||
// the first core is enough.
|
||||
scanner := bufio.NewScanner(cpuinfo)
|
||||
for scanner.Scan() {
|
||||
newline := scanner.Text()
|
||||
list := strings.Split(newline, ":")
|
||||
|
||||
if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
|
||||
return strings.TrimSpace(list[1]), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the scanner encountered errors
|
||||
err = scanner.Err()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "", errors.Wrapf(errdefs.ErrNotFound, "getCPUInfo for pattern: %s", pattern)
|
||||
}
|
||||
|
||||
func getCPUVariant() string {
|
||||
variant, err := getCPUInfo("Cpu architecture")
|
||||
if err != nil {
|
||||
log.L.WithError(err).Error("failure getting variant")
|
||||
return ""
|
||||
}
|
||||
|
||||
switch variant {
|
||||
case "8":
|
||||
variant = "v8"
|
||||
case "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
|
||||
variant = "v7"
|
||||
case "6", "6TEJ":
|
||||
variant = "v6"
|
||||
case "5", "5T", "5TE", "5TEJ":
|
||||
variant = "v5"
|
||||
case "4", "4T":
|
||||
variant = "v4"
|
||||
case "3":
|
||||
variant = "v3"
|
||||
default:
|
||||
variant = "unknown"
|
||||
}
|
||||
|
||||
return variant
|
||||
}
|
24
platforms/cpuinfo_test.go
Normal file
24
platforms/cpuinfo_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
package platforms
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCPUVariant(t *testing.T) {
|
||||
if !isArmArch(runtime.GOARCH) || !isLinuxOS(runtime.GOOS) {
|
||||
t.Skip("only relevant on linux/arm")
|
||||
}
|
||||
|
||||
variants := []string{"v8", "v7", "v6", "v5", "v4", "v3"}
|
||||
|
||||
p := getCPUVariant()
|
||||
for _, variant := range variants {
|
||||
if p == variant {
|
||||
t.Logf("got valid variant as expected: %#v = %#v\n", p, variant)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("could not get valid variant as expected: %v\n", variants)
|
||||
}
|
@ -5,6 +5,13 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// isLinuxOS returns true if the operating system is Linux.
|
||||
//
|
||||
// The OS value should be normalized before calling this function.
|
||||
func isLinuxOS(os string) bool {
|
||||
return os == "linux"
|
||||
}
|
||||
|
||||
// These function are generated from from https://golang.org/src/go/build/syslist.go.
|
||||
//
|
||||
// We use switch statements because they are slightly faster than map lookups
|
||||
@ -21,6 +28,17 @@ func isKnownOS(os string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isArmArch returns true if the architecture is ARM.
|
||||
//
|
||||
// The arch value should be normalized before being passed to this function.
|
||||
func isArmArch(arch string) bool {
|
||||
switch arch {
|
||||
case "arm", "arm64":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isKnownArch returns true if we know about the architecture.
|
||||
//
|
||||
// The arch value should be normalized before being passed to this function.
|
||||
|
@ -16,6 +16,7 @@ func DefaultSpec() specs.Platform {
|
||||
return specs.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
// TODO(stevvooe): Need to resolve GOARM for arm hosts.
|
||||
// The Variant field will be empty if arch != ARM.
|
||||
Variant: cpuVariant,
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ func TestDefault(t *testing.T) {
|
||||
expected := specs.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
Variant: cpuVariant,
|
||||
}
|
||||
p := DefaultSpec()
|
||||
if !reflect.DeepEqual(p, expected) {
|
||||
|
Loading…
Reference in New Issue
Block a user