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 }