File: series_linux.go

package info (click to toggle)
golang-github-juju-utils 0.0~git20171220.f38c0b0-6
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,748 kB
  • sloc: makefile: 20
file content (147 lines) | stat: -rw-r--r-- 3,935 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package series

import (
	"encoding/csv"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/juju/errors"
	jujuos "github.com/juju/utils/os"
)

var (
	// osReleaseFile is the name of the file that is read in order to determine
	// the linux type release version.
	osReleaseFile = "/etc/os-release"
)

func readSeries() (string, error) {
	values, err := jujuos.ReadOSRelease(osReleaseFile)
	if err != nil {
		return "unknown", err
	}
	updateSeriesVersionsOnce()
	return seriesFromOSRelease(values)
}

func seriesFromOSRelease(values map[string]string) (string, error) {
	switch values["ID"] {
	case strings.ToLower(jujuos.Ubuntu.String()):
		return getValue(ubuntuSeries, values["VERSION_ID"])
	case strings.ToLower(jujuos.CentOS.String()):
		codename := fmt.Sprintf("%s%s", values["ID"], values["VERSION_ID"])
		return getValue(centosSeries, codename)
	case strings.ToLower(jujuos.OpenSUSE.String()):
		codename := fmt.Sprintf("%s%s",
			values["ID"],
			strings.Split(values["VERSION_ID"], ".")[0])
		return getValue(opensuseSeries, codename)
	default:
		return genericLinuxSeries, nil
	}
}

func getValue(from map[string]string, val string) (string, error) {
	for serie, ver := range from {
		if ver == val {
			return serie, nil
		}
	}
	return "unknown", errors.New("could not determine series")
}

// ReleaseVersion looks for the value of VERSION_ID in the content of
// the os-release.  If the value is not found, the file is not found, or
// an error occurs reading the file, an empty string is returned.
func ReleaseVersion() string {
	release, err := jujuos.ReadOSRelease(osReleaseFile)
	if err != nil {
		return ""
	}
	return release["VERSION_ID"]
}

func updateLocalSeriesVersions() error {
	return updateDistroInfo()
}

var distroInfo = "/usr/share/distro-info/ubuntu.csv"

// updateDistroInfo updates seriesVersions from /usr/share/distro-info/ubuntu.csv if possible..
func updateDistroInfo() error {
	// We need to find the series version eg 12.04 from the series eg precise. Use the information found in
	// /usr/share/distro-info/ubuntu.csv provided by distro-info-data package.
	f, err := os.Open(distroInfo)
	if err != nil {
		// On non-Ubuntu systems this file won't exist but that's expected.
		return nil
	}
	defer f.Close()

	csvReader := csv.NewReader(f)
	csvReader.FieldsPerRecord = -1
	records, err := csvReader.ReadAll()
	if err != nil {
		return errors.Annotatef(err, "reading %s", distroInfo)
	}
	fieldNames := records[0]
	records = records[1:]

	// We ignore all series prior to precise.
	//
	// TODO(axw) only add in series that are supported? (i.e. before end of life)
	// Can we really do this? Users might have Extended Security Maintenance.

	now := time.Now()
	var foundPrecise bool
	for _, fields := range records {
		var version, series string
		var release string
		for i, field := range fields {
			if i >= len(fieldNames) {
				break
			}
			switch fieldNames[i] {
			case "version":
				version = field
			case "series":
				series = field
			case "release":
				release = field
			}
		}
		if version == "" || series == "" || release == "" {
			// Ignore malformed line.
			continue
		}
		if !foundPrecise {
			if series != "precise" {
				continue
			}
			foundPrecise = true
		}

		releaseDate, err := time.Parse("2006-01-02", release)
		if err != nil {
			// Ignore lines with invalid release dates.
			continue
		}

		// The numeric version may contain a LTS moniker so strip that out.
		trimmedVersion := strings.TrimSuffix(version, " LTS")
		seriesVersions[series] = trimmedVersion
		ubuntuSeries[series] = trimmedVersion
		if trimmedVersion != version && !now.Before(releaseDate) {
			// We only record that a series is LTS if its release
			// date has passed. This allows the series to be tested
			// pre-release, without affecting default series.
			ubuntuLTS[series] = true
		}
	}
	return nil
}