forked from bsteciuk/kismatic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
about.go
141 lines (120 loc) · 4.18 KB
/
about.go
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
package install
import (
"fmt"
"strings"
"github.com/apprenda/kismatic/pkg/ssh"
"github.com/apprenda/kismatic/pkg/util"
"github.com/blang/semver"
yaml "gopkg.in/yaml.v2"
)
// ClusterVersion contains version information about the cluster
type ClusterVersion struct {
EarliestVersion semver.Version
LatestVersion semver.Version
IsTransitioning bool
Nodes []ListableNode
}
// ListableNode contains version and role information about a given node
type ListableNode struct {
Node Node
Roles []string
Version semver.Version
ComponentVersions ComponentVersions
}
type ComponentVersions struct {
Kubernetes string
}
// KismaticVersion contains the version information of the currently running binary
var KismaticVersion semver.Version
// SetVersion parses the given version, and sets it as the global version of the binary
func SetVersion(v string) {
ver, err := parseVersion(v)
if err != nil {
panic("failed to parse version " + v)
}
KismaticVersion = ver
}
// IsOlderVersion returns true if the provided version is older than the current Kismatic version
func IsOlderVersion(that semver.Version) bool {
this := KismaticVersion
return this.GT(that)
}
// IsLessThanVersion parses the version from a string and returns true if this version is less than that version
func IsLessThanVersion(this semver.Version, that string) bool {
thatVersion, err := parseVersion(that)
if err != nil {
panic("failed to parse version " + that)
}
return this.LT(thatVersion)
}
// ListVersions connects to the cluster described in the plan file and
// gathers version information about it.
func ListVersions(plan *Plan) (ClusterVersion, error) {
nodes := plan.GetUniqueNodes()
cv := ClusterVersion{
Nodes: []ListableNode{},
}
sshDeets := plan.Cluster.SSH
ketVerFile := "/etc/kismatic-version"
componentVerFile := "/etc/component-versions"
for i, node := range nodes {
client, err := ssh.NewClient(node.IP, sshDeets.Port, sshDeets.User, sshDeets.Key)
if err != nil {
return cv, fmt.Errorf("error creating SSH client: %v", err)
}
// get KET version
ketOutput, err := client.Output(false, fmt.Sprintf("cat %s", ketVerFile))
if err != nil {
// the output var contains the actual error message from the cat command, which has
// more meaningful info
return cv, fmt.Errorf("error getting KET version for node %q: %q", node.Host, ketOutput)
}
thisVersion, err := parseVersion(ketOutput)
if err != nil {
return cv, fmt.Errorf("invalid version %q found in version file %q of node %s", ketOutput, ketVerFile, node.Host)
}
// get component versions
versionsOutput, err := client.Output(false, fmt.Sprintf("cat %s", componentVerFile))
// don't fail if the file is not found, will default to empty
// TODO remove
if err != nil && !strings.Contains(versionsOutput, "No such file or directory") {
// the output var contains the actual error message from the cat command, which has
// more meaningful info
return cv, fmt.Errorf("error getting component versions for node %q: %q", node.Host, versionsOutput)
}
versions := ComponentVersions{}
if !strings.Contains(versionsOutput, "No such file or directory") {
err = yaml.Unmarshal([]byte(versionsOutput), &versions)
if err != nil {
return cv, fmt.Errorf("error unmarshalling component versions file: %q", componentVerFile)
}
}
cv.Nodes = append(cv.Nodes, ListableNode{node, plan.GetRolesForIP(node.IP), thisVersion, versions})
// If looking at the first node, set the versions and move on
if i == 0 {
cv.EarliestVersion = thisVersion
cv.LatestVersion = thisVersion
continue
}
if thisVersion.GT(cv.LatestVersion) {
cv.LatestVersion = thisVersion
}
if cv.EarliestVersion.GT(thisVersion) {
cv.EarliestVersion = thisVersion
}
}
cv.IsTransitioning = cv.EarliestVersion.NE(cv.LatestVersion)
return cv, nil
}
// NodesWithRoles returns a filtered list of ListableNode slice based on the node's roles
func NodesWithRoles(nodes []ListableNode, roles ...string) []ListableNode {
var subset []ListableNode
for _, need := range roles {
for _, n := range nodes {
if util.Subset([]string{need}, n.Roles) {
subset = append(subset, n)
}
}
}
return subset
}