-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathtypes.go
197 lines (179 loc) · 4.52 KB
/
types.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package common
import (
"math"
"strings"
"time"
)
// ProfileType defines the type of KPIProfiles.
type ProfileType int
const (
Obsolete ProfileType = iota
Latency
Availability
Throughput
Power
)
// ProfileTypeFromText converts string into the right int.
func ProfileTypeFromText(text string) ProfileType {
switch strings.ToLower(text) {
default:
return Obsolete
case "latency":
return Latency
case "availability":
return Availability
case "throughput":
return Throughput
case "power":
return Power
}
}
// PodError holds start and end time for an error of a POD.
type PodError struct {
Key string
Start time.Time
End time.Time
Created time.Time
// TODO: look into adding reason for failure etc.
}
// Profile holds information about valid objective profiles.
type Profile struct {
Key string
ProfileType ProfileType
Query string
External bool
Address string
}
// Intent holds information about an intent in the system.
type Intent struct {
Key string
Priority float64
TargetKey string
TargetKind string
Objectives map[string]float64
}
// PodState represents the state of an POD.
type PodState struct {
Availability float64
NodeName string
State string
QoSClass string
}
// State represents the state a set of PODs can be in.
type State struct {
Intent Intent
CurrentPods map[string]PodState
CurrentData map[string]map[string]float64
Resources map[string]int64
Annotations map[string]string
}
// DeepCopy creates a deep copy of a state.
func (one *State) DeepCopy() State {
// make sure we capture the objectives.
objective := Intent{
Key: one.Intent.Key,
Priority: one.Intent.Priority,
TargetKey: one.Intent.TargetKey,
TargetKind: one.Intent.TargetKind,
Objectives: map[string]float64{},
}
for k, v := range one.Intent.Objectives {
objective.Objectives[k] = v
}
// new state.
tmp := State{
objective,
map[string]PodState{},
map[string]map[string]float64{},
map[string]int64{},
map[string]string{},
}
// copy over pod states.
pods := map[string]PodState{}
for k, v := range one.CurrentPods {
state := PodState{
v.Availability,
v.NodeName,
v.State,
v.QoSClass,
}
pods[k] = state
}
tmp.CurrentPods = pods
// annotations and resources
if one.Resources == nil {
tmp.Resources = nil
} else {
for rk, rv := range one.Resources {
tmp.Resources[rk] = rv
}
}
if one.Annotations == nil {
tmp.Annotations = nil
} else {
for ak, av := range one.Annotations {
tmp.Annotations[ak] = av
}
}
// and all the rest.
for k := range one.CurrentData {
subMap := map[string]float64{}
for a, b := range one.CurrentData[k] {
subMap[a] = b
}
tmp.CurrentData[k] = subMap
}
return tmp
}
// Distance calculates the euclidean Distance between two states. Potentially we can add weights here maybe - or another way to calculate the Distance so e.g. the Distance for P99 is more important than the Distance in P50 latency.
func (one *State) Distance(another *State, profiles map[string]Profile) float64 {
squaresSum := 0.0
for key, val := range one.Intent.Objectives {
squaresSum += math.Pow(val-another.Intent.Objectives[key], 2)
}
if one.IsBetter(another, profiles) && squaresSum != 0.0 {
// we should favor states which are closer to the goal...
return -1 / math.Sqrt(squaresSum)
}
return math.Sqrt(squaresSum)
}
// IsBetter compares the objectives of one state to another - returns true if all latency or power related objective targets are smaller or equal, and all others are larger or equal.
func (one *State) IsBetter(another *State, profiles map[string]Profile) bool {
if len(one.Intent.Objectives) != len(another.Intent.Objectives) {
return false
}
res := false
for k, v := range one.Intent.Objectives {
// TODO: make this configurable through the KPI profiles for which we define larger or smaller is better.
if profiles[k].ProfileType == ProfileTypeFromText("latency") || profiles[k].ProfileType == ProfileTypeFromText("power") {
if v <= another.Intent.Objectives[k] {
res = true
} else {
return false
}
} else {
if v >= another.Intent.Objectives[k] {
res = true
} else {
return false
}
}
}
return res
}
// LessResources contrast the resources and returns true if one state has less resource than another.
func (one *State) LessResources(another *State) bool {
res := false
for k, v := range one.Resources {
tmp, ok := another.Resources[k]
if !ok {
return false
}
if v <= tmp {
res = true
} else {
return false
}
}
return res
}