github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/version/osversion.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package version 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "strconv" 10 "strings" 11 12 "github.com/juju/errors" 13 "github.com/juju/loggo" 14 ) 15 16 var logger = loggo.GetLogger("juju.version") 17 18 // mustOSVersion will panic if the osVersion is "unknown" due 19 // to an error. 20 // 21 // If you want to avoid the panic, call osVersion and handle 22 // the error. 23 func mustOSVersion() string { 24 version, err := osVersion() 25 if err != nil { 26 panic("osVersion reported an error: " + err.Error()) 27 } 28 return version 29 } 30 31 // MustOSFromSeries will panic if the series represents an "unknown" 32 // operating system 33 func MustOSFromSeries(series string) OSType { 34 operatingSystem, err := GetOSFromSeries(series) 35 if err != nil { 36 panic("osVersion reported an error: " + err.Error()) 37 } 38 return operatingSystem 39 } 40 41 func readOSRelease() (map[string]string, error) { 42 values := map[string]string{} 43 44 contents, err := ioutil.ReadFile(osReleaseFile) 45 if err != nil { 46 return values, err 47 } 48 releaseDetails := strings.Split(string(contents), "\n") 49 for _, val := range releaseDetails { 50 c := strings.SplitN(val, "=", 2) 51 if len(c) != 2 { 52 continue 53 } 54 values[c[0]] = strings.Trim(c[1], "\t '\"") 55 } 56 id, ok := values["ID"] 57 if !ok { 58 return values, errors.New("OS release file is missing ID") 59 } 60 if _, ok := values["VERSION_ID"]; !ok { 61 values["VERSION_ID"], ok = defaultVersionIDs[id] 62 if !ok { 63 return values, errors.New("OS release file is missing VERSION_ID") 64 } 65 } 66 return values, nil 67 } 68 69 func getValue(from map[string]string, val string) (string, error) { 70 for serie, ver := range from { 71 if ver == val { 72 return serie, nil 73 } 74 } 75 return "unknown", errors.New("Could not determine series") 76 } 77 78 func readSeries() (string, error) { 79 values, err := readOSRelease() 80 if err != nil { 81 return "unknown", err 82 } 83 updateSeriesVersions() 84 switch values["ID"] { 85 case strings.ToLower(Ubuntu.String()): 86 return getValue(ubuntuSeries, values["VERSION_ID"]) 87 case strings.ToLower(Arch.String()): 88 return getValue(archSeries, values["VERSION_ID"]) 89 case strings.ToLower(CentOS.String()): 90 codename := fmt.Sprintf("%s%s", values["ID"], values["VERSION_ID"]) 91 return getValue(centosSeries, codename) 92 default: 93 return "unknown", nil 94 } 95 } 96 97 // kernelToMajor takes a dotted version and returns just the Major portion 98 func kernelToMajor(getKernelVersion func() (string, error)) (int, error) { 99 fullVersion, err := getKernelVersion() 100 if err != nil { 101 return 0, err 102 } 103 parts := strings.SplitN(fullVersion, ".", 2) 104 majorVersion, err := strconv.ParseInt(parts[0], 10, 32) 105 if err != nil { 106 return 0, err 107 } 108 return int(majorVersion), nil 109 } 110 111 func macOSXSeriesFromKernelVersion(getKernelVersion func() (string, error)) (string, error) { 112 majorVersion, err := kernelToMajor(getKernelVersion) 113 if err != nil { 114 logger.Infof("unable to determine OS version: %v", err) 115 return "unknown", err 116 } 117 return macOSXSeriesFromMajorVersion(majorVersion) 118 } 119 120 // TODO(jam): 2014-05-06 https://launchpad.net/bugs/1316593 121 // we should have a system file that we can read so this can be updated without 122 // recompiling Juju. For now, this is a lot easier, and also solves the fact 123 // that we want to populate version.Current.Series during init() time, before 124 // we've potentially read that information from anywhere else 125 // macOSXSeries maps from the Darwin Kernel Major Version to the Mac OSX 126 // series. 127 var macOSXSeries = map[int]string{ 128 15: "elcapitan", 129 14: "yosemite", 130 13: "mavericks", 131 12: "mountainlion", 132 11: "lion", 133 10: "snowleopard", 134 9: "leopard", 135 8: "tiger", 136 7: "panther", 137 6: "jaguar", 138 5: "puma", 139 } 140 141 func macOSXSeriesFromMajorVersion(majorVersion int) (string, error) { 142 series, ok := macOSXSeries[majorVersion] 143 if !ok { 144 return "unknown", errors.Errorf("unknown series %q", series) 145 } 146 return series, nil 147 }