github.com/prysmaticlabs/prysm@v1.4.4/shared/prereq/prereq.go (about)

     1  package prereq
     2  
     3  import (
     4  	"context"
     5  	"os/exec"
     6  	"runtime"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/pkg/errors"
    11  	log "github.com/sirupsen/logrus"
    12  )
    13  
    14  type platform struct {
    15  	os           string
    16  	arch         string
    17  	majorVersion int
    18  	minorVersion int
    19  }
    20  
    21  var (
    22  	// execShellOutput has execShellOutputFunc as the default but can be changed for testing purposes.
    23  	execShellOutput = execShellOutputFunc
    24  	runtimeOS       = runtime.GOOS
    25  	runtimeArch     = runtime.GOARCH
    26  )
    27  
    28  // execShellOutputFunc passes a command and args to exec.CommandContext and returns the result as a string
    29  func execShellOutputFunc(ctx context.Context, command string, args ...string) (string, error) {
    30  	result, err := exec.CommandContext(ctx, command, args...).Output()
    31  	if err != nil {
    32  		return "", errors.Wrap(err, "error in command execution")
    33  	}
    34  	return string(result), nil
    35  }
    36  
    37  func supportedPlatforms() []platform {
    38  	return []platform{
    39  		{os: "linux", arch: "amd64"},
    40  		{os: "linux", arch: "arm64"},
    41  		{os: "darwin", arch: "amd64", majorVersion: 10, minorVersion: 14},
    42  		{os: "windows", arch: "amd64"},
    43  	}
    44  }
    45  
    46  // parseVersion takes a string and splits it using sep separator, and outputs a slice of integers
    47  // corresponding to version numbers.  If it cannot find num level of versions, it returns an error
    48  func parseVersion(input string, num int, sep string) ([]int, error) {
    49  	var version = make([]int, num)
    50  	components := strings.Split(input, sep)
    51  	for i, component := range components {
    52  		components[i] = strings.TrimSpace(component)
    53  	}
    54  	if len(components) < num {
    55  		return nil, errors.New("insufficient information about version")
    56  	}
    57  	for i := range version {
    58  		var err error
    59  		version[i], err = strconv.Atoi(components[i])
    60  		if err != nil {
    61  			return nil, errors.Wrap(err, "error during conversion")
    62  		}
    63  	}
    64  	return version, nil
    65  }
    66  
    67  // meetsMinPlatformReqs returns true if the runtime matches any on the list of supported platforms
    68  func meetsMinPlatformReqs(ctx context.Context) (bool, error) {
    69  	okPlatforms := supportedPlatforms()
    70  	for _, platform := range okPlatforms {
    71  		if runtimeOS == platform.os && runtimeArch == platform.arch {
    72  			// If MacOS we make sure it meets the minimum version cutoff
    73  			if runtimeOS == "darwin" {
    74  				versionStr, err := execShellOutput(ctx, "uname", "-r")
    75  				if err != nil {
    76  					return false, errors.Wrap(err, "error obtaining MacOS version")
    77  				}
    78  				version, err := parseVersion(versionStr, 2, ".")
    79  				if err != nil {
    80  					return false, errors.Wrap(err, "error parsing version")
    81  				}
    82  				if version[0] != platform.majorVersion {
    83  					return version[0] > platform.majorVersion, nil
    84  				}
    85  				if version[1] < platform.minorVersion {
    86  					return false, nil
    87  				}
    88  				return true, nil
    89  			}
    90  			// Otherwise we have a match between runtime and our list of accepted platforms
    91  			return true, nil
    92  		}
    93  	}
    94  	return false, nil
    95  }
    96  
    97  // WarnIfPlatformNotSupported warns if the user's platform is not supported or if it fails to detect user's platform
    98  func WarnIfPlatformNotSupported(ctx context.Context) {
    99  	supported, err := meetsMinPlatformReqs(ctx)
   100  	if err != nil {
   101  		log.Warnf("Failed to detect host platform:  %v", err)
   102  		return
   103  	}
   104  	if !supported {
   105  		log.Warn("This platform is not supported. The following platforms are supported: Linux/AMD64," +
   106  			" Linux/ARM64, Mac OS X/AMD64 (10.14+ only), and Windows/AMD64")
   107  	}
   108  }