github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/version/ubuntu/supportedseries.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ubuntu
     5  
     6  import (
     7  	"bufio"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"strings"
    12  	"sync"
    13  
    14  	"github.com/juju/loggo"
    15  )
    16  
    17  var logger = loggo.GetLogger("juju.ubuntu")
    18  
    19  // seriesVersions provides a mapping between Ubuntu series names and version numbers.
    20  // The values here are current as of the time of writing. On Ubuntu systems, we update
    21  // these values from /usr/share/distro-info/ubuntu.csv to ensure we have the latest values.
    22  // On non-Ubuntu systems, these values provide a nice fallback option.
    23  // Exported so tests can change the values to ensure the distro-info lookup works.
    24  var seriesVersions = map[string]string{
    25  	"precise": "12.04",
    26  	"quantal": "12.10",
    27  	"raring":  "13.04",
    28  	"saucy":   "13.10",
    29  	"trusty":  "14.04",
    30  	"utopic":  "14.10",
    31  }
    32  
    33  var (
    34  	seriesVersionsMutex   sync.Mutex
    35  	updatedseriesVersions bool
    36  )
    37  
    38  // SeriesVersion returns the version number for the specified Ubuntu series.
    39  func SeriesVersion(series string) (string, error) {
    40  	if series == "" {
    41  		panic("cannot pass empty series to SeriesVersion()")
    42  	}
    43  	seriesVersionsMutex.Lock()
    44  	defer seriesVersionsMutex.Unlock()
    45  	if vers, ok := seriesVersions[series]; ok {
    46  		return vers, nil
    47  	}
    48  	updateSeriesVersions()
    49  	if vers, ok := seriesVersions[series]; ok {
    50  		return vers, nil
    51  	}
    52  	return "", fmt.Errorf("invalid series %q", series)
    53  }
    54  
    55  // SupportedSeries returns the Ubuntu series on which we can run Juju workloads.
    56  func SupportedSeries() []string {
    57  	seriesVersionsMutex.Lock()
    58  	defer seriesVersionsMutex.Unlock()
    59  	updateSeriesVersions()
    60  	var series []string
    61  	for s := range seriesVersions {
    62  		series = append(series, s)
    63  	}
    64  	return series
    65  }
    66  
    67  func updateSeriesVersions() {
    68  	if !updatedseriesVersions {
    69  		err := updateDistroInfo()
    70  		if err != nil {
    71  			logger.Warningf("failed to update distro info: %v", err)
    72  		}
    73  		updatedseriesVersions = true
    74  	}
    75  }
    76  
    77  // updateDistroInfo updates seriesVersions from /usr/share/distro-info/ubuntu.csv if possible..
    78  func updateDistroInfo() error {
    79  	// We need to find the series version eg 12.04 from the series eg precise. Use the information found in
    80  	// /usr/share/distro-info/ubuntu.csv provided by distro-info-data package.
    81  	f, err := os.Open("/usr/share/distro-info/ubuntu.csv")
    82  	if err != nil {
    83  		// On non-Ubuntu systems this file won't exist but that's expected.
    84  		return nil
    85  	}
    86  	defer f.Close()
    87  	bufRdr := bufio.NewReader(f)
    88  	// Only find info for precise or later.
    89  	preciseOrLaterFound := false
    90  	for {
    91  		line, err := bufRdr.ReadString('\n')
    92  		if err == io.EOF {
    93  			break
    94  		}
    95  		if err != nil {
    96  			return fmt.Errorf("reading distro info file file: %v", err)
    97  		}
    98  		// lines are of the form: "12.04 LTS,Precise Pangolin,precise,2011-10-13,2012-04-26,2017-04-26"
    99  		parts := strings.Split(line, ",")
   100  		// Ignore any malformed lines.
   101  		if len(parts) < 3 {
   102  			continue
   103  		}
   104  		series := parts[2]
   105  		if series == "precise" {
   106  			preciseOrLaterFound = true
   107  		}
   108  		if series != "precise" && !preciseOrLaterFound {
   109  			continue
   110  		}
   111  		// the numeric version may contain a LTS moniker so strip that out.
   112  		seriesInfo := strings.Split(parts[0], " ")
   113  		seriesVersions[series] = seriesInfo[0]
   114  	}
   115  	return nil
   116  }