github.com/hashicorp/packer@v1.14.3/internal/hcp/registry/metadata/os.go (about)

     1  package metadata
     2  
     3  import (
     4  	"log"
     5  	"os/exec"
     6  	"runtime"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  type OSInfo struct {
    12  	Name    string
    13  	Arch    string
    14  	Version string
    15  }
    16  
    17  // CommandExecutor is an interface for executing commands.
    18  type CommandExecutor interface {
    19  	Exec(name string, arg ...string) ([]byte, error)
    20  }
    21  
    22  // DefaultExecutor is the default implementation of CommandExecutor.
    23  type DefaultExecutor struct{}
    24  
    25  // Exec executes a command and returns the combined output.
    26  func (d DefaultExecutor) Exec(name string, arg ...string) ([]byte, error) {
    27  	cmd := exec.Command(name, arg...)
    28  	return cmd.CombinedOutput()
    29  }
    30  
    31  var executor CommandExecutor = DefaultExecutor{}
    32  
    33  func GetOSMetadata() map[string]interface{} {
    34  	var osInfo OSInfo
    35  
    36  	switch runtime.GOOS {
    37  	case "windows":
    38  		osInfo = GetInfoForWindows(executor)
    39  	case "darwin":
    40  		osInfo = GetInfo(executor, "-srm")
    41  	case "linux":
    42  		osInfo = GetInfo(executor, "-srio")
    43  	case "freebsd":
    44  		osInfo = GetInfo(executor, "-sri")
    45  	case "openbsd":
    46  		osInfo = GetInfo(executor, "-srm")
    47  	case "netbsd":
    48  		osInfo = GetInfo(executor, "-srm")
    49  	default:
    50  		osInfo = OSInfo{
    51  			Name: runtime.GOOS,
    52  			Arch: runtime.GOARCH,
    53  		}
    54  	}
    55  
    56  	return map[string]interface{}{
    57  		"type": osInfo.Name,
    58  		"details": map[string]interface{}{
    59  			"arch":    osInfo.Arch,
    60  			"version": osInfo.Version,
    61  		},
    62  	}
    63  }
    64  
    65  func GetInfo(exec CommandExecutor, flags string) OSInfo {
    66  	out, err := uname(exec, flags)
    67  	tries := 0
    68  	for strings.Contains(out, "broken pipe") && tries < 3 {
    69  		out, err = uname(exec, flags)
    70  		time.Sleep(500 * time.Millisecond)
    71  		tries++
    72  	}
    73  	if strings.Contains(out, "broken pipe") || err != nil {
    74  		out = ""
    75  	}
    76  
    77  	if err != nil {
    78  		log.Printf("[ERROR] failed to get the OS info: %s", err)
    79  	}
    80  	core := retrieveCore(out)
    81  	return OSInfo{
    82  		Name:    runtime.GOOS,
    83  		Arch:    runtime.GOARCH,
    84  		Version: core,
    85  	}
    86  }
    87  
    88  func uname(exec CommandExecutor, flags string) (string, error) {
    89  	output, err := exec.Exec("uname", flags)
    90  	return string(output), err
    91  }
    92  
    93  func retrieveCore(osStr string) string {
    94  	osStr = strings.Replace(osStr, "\n", "", -1)
    95  	osStr = strings.Replace(osStr, "\r\n", "", -1)
    96  	osInfo := strings.Split(osStr, " ")
    97  
    98  	var core string
    99  	if len(osInfo) > 1 {
   100  		core = osInfo[1]
   101  	}
   102  	return core
   103  }
   104  
   105  func GetInfoForWindows(exec CommandExecutor) OSInfo {
   106  	out, err := exec.Exec("cmd", "ver")
   107  	if err != nil {
   108  		log.Printf("[ERROR] failed to get the OS info: %s", err)
   109  		return OSInfo{
   110  			Name: runtime.GOOS,
   111  			Arch: runtime.GOARCH,
   112  		}
   113  	}
   114  
   115  	osStr := strings.Replace(string(out), "\n", "", -1)
   116  	osStr = strings.Replace(osStr, "\r\n", "", -1)
   117  	tmp1 := strings.Index(osStr, "[Version")
   118  	tmp2 := strings.Index(osStr, "]")
   119  	var ver string
   120  	if tmp1 == -1 || tmp2 == -1 {
   121  		ver = ""
   122  	} else {
   123  		ver = osStr[tmp1+9 : tmp2]
   124  	}
   125  
   126  	osInfo := OSInfo{
   127  		Name:    runtime.GOOS,
   128  		Arch:    runtime.GOARCH,
   129  		Version: ver,
   130  	}
   131  	return osInfo
   132  }