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  }