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