forked from k8snetworkplumbingwg/ptp-operator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecommend.go
175 lines (146 loc) · 4.55 KB
/
recommend.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
package controllers
import (
"fmt"
"sort"
"github.com/golang/glog"
corev1 "k8s.io/api/core/v1"
ptpv1 "github.com/k8snetworkplumbingwg/ptp-operator/api/v1"
)
func printWhenNotNil(p interface{}, description string) {
switch v := p.(type) {
case *string:
if v != nil {
glog.Info(description, ": ", *v)
}
case *int64:
if v != nil {
glog.Info(description, ": ", *v)
}
default:
glog.Info(description, ": ", v)
}
}
// getRecommendNodePtpProfiles return recommended node ptp profile
func getRecommendNodePtpProfiles(ptpConfigList *ptpv1.PtpConfigList, node corev1.Node) ([]ptpv1.PtpProfile, error) {
glog.V(2).Infof("in getRecommendNodePtpProfiles")
profiles, err := getRecommendProfiles(ptpConfigList, node)
if err != nil {
return nil, fmt.Errorf("get recommended ptp profiles failed: %v", err)
}
glog.Infof("ptp profiles to be updated for node: %s", node.Name)
for _, profile := range profiles {
glog.Infof("------------------------------------")
printWhenNotNil(profile.Name, "Profile Name")
printWhenNotNil(profile.Interface, "Interface")
printWhenNotNil(profile.Ptp4lOpts, "Ptp4lOpts")
printWhenNotNil(profile.Phc2sysOpts, "Phc2sysOpts")
printWhenNotNil(profile.Ptp4lConf, "Ptp4lConf")
printWhenNotNil(profile.PtpSchedulingPolicy, "PtpSchedulingPolicy")
printWhenNotNil(profile.PtpSchedulingPriority, "PtpSchedulingPriority")
glog.Infof("------------------------------------")
}
return profiles, nil
}
func getRecommendProfiles(ptpConfigList *ptpv1.PtpConfigList, node corev1.Node) ([]ptpv1.PtpProfile, error) {
glog.V(2).Infof("In getRecommendProfiles")
profilesNames := getRecommendProfilesNames(ptpConfigList, node)
glog.V(2).Infof("recommended ptp profiles names are %v for node: %s", returnMapKeys(profilesNames), node.Name)
profiles := []ptpv1.PtpProfile{}
for _, cfg := range ptpConfigList.Items {
if cfg.Spec.Profile != nil {
for _, profile := range cfg.Spec.Profile {
if _, exist := profilesNames[*profile.Name]; exist {
profiles = append(profiles, profile)
}
}
}
}
if len(profiles) != len(profilesNames) {
return nil, fmt.Errorf("failed to find all the profiles")
}
// sort profiles by name
sort.SliceStable(profiles, func(i, j int) bool {
return *profiles[i].Name < *profiles[j].Name
})
return profiles, nil
}
func getRecommendProfilesNames(ptpConfigList *ptpv1.PtpConfigList, node corev1.Node) map[string]interface{} {
glog.V(2).Infof("In getRecommendProfilesNames")
var (
allRecommend []ptpv1.PtpRecommend
)
// append recommend section from each custom resource into one list
for _, cfg := range ptpConfigList.Items {
if cfg.Spec.Recommend != nil {
allRecommend = append(allRecommend, cfg.Spec.Recommend...)
}
}
// allRecommend sorted by priority
// priority 0 will become the first item in allRecommend
sort.Slice(allRecommend, func(i, j int) bool {
if allRecommend[i].Priority != nil && allRecommend[j].Priority != nil {
return *allRecommend[i].Priority < *allRecommend[j].Priority
}
return allRecommend[i].Priority != nil
})
// Add all the profiles with the same priority
profilesNames := make(map[string]interface{})
foundPolicy := false
priority := int64(-1)
// loop allRecommend from high priority(0) to low(*)
for _, r := range allRecommend {
// ignore if profile not define in recommend
if r.Profile == nil {
continue
}
// ignore if match section is empty
if len(r.Match) == 0 {
continue
}
// check if the policy match the node
switch {
case !nodeMatches(&node, r.Match):
continue
case !foundPolicy:
profilesNames[*r.Profile] = struct{}{}
priority = *r.Priority
foundPolicy = true
case *r.Priority == priority:
profilesNames[*r.Profile] = struct{}{}
default:
break
}
}
return profilesNames
}
func nodeMatches(node *corev1.Node, matchRuleList []ptpv1.MatchRule) bool {
// loop over Match list
for _, m := range matchRuleList {
// nodeName has higher priority than nodeLabel
// return immediately if nodeName matches
// make sure m.NodeName pointer is not nil before
// comparing values
if m.NodeName != nil && *m.NodeName == node.Name {
return true
}
// return immediately when label matches
// this makes sure priority field is respected
for k := range node.Labels {
// make sure m.NodeLabel pointer is not nil before
// comparing values
if m.NodeLabel != nil && *m.NodeLabel == k {
return true
}
}
}
return false
}
func returnMapKeys(profiles map[string]interface{}) []string {
keys := make([]string, len(profiles))
i := 0
for k := range profiles {
keys[i] = k
i++
}
return keys
}