Skip to content

Commit 112b5e7

Browse files
committed
Add GetCachedSupportedFeatures method to hcn package
To avoid a breaking change on GetSupportedFeatures introduce a new GetCachedSupportedFeatures method. This method does the feature check and version parsing once and then assigns a global with the information. This can be used to optimize for situations where many uses of the hcn.IsXSupported methods are going to be used (kube-proxy for example). Signed-off-by: Daniel Canter <[email protected]>
1 parent 2b5a08d commit 112b5e7

2 files changed

Lines changed: 125 additions & 28 deletions

File tree

hcn/hcn.go

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ func platformDoesNotSupportError(featureName string) error {
127127

128128
// V2ApiSupported returns an error if the HCN version does not support the V2 Apis.
129129
func V2ApiSupported() error {
130-
supported := GetSupportedFeatures()
130+
supported, err := GetCachedSupportedFeatures()
131+
if err != nil {
132+
return err
133+
}
131134
if supported.Api.V2 {
132135
return nil
133136
}
@@ -143,7 +146,10 @@ func V2SchemaVersion() SchemaVersion {
143146

144147
// RemoteSubnetSupported returns an error if the HCN version does not support Remote Subnet policies.
145148
func RemoteSubnetSupported() error {
146-
supported := GetSupportedFeatures()
149+
supported, err := GetCachedSupportedFeatures()
150+
if err != nil {
151+
return err
152+
}
147153
if supported.RemoteSubnet {
148154
return nil
149155
}
@@ -152,7 +158,10 @@ func RemoteSubnetSupported() error {
152158

153159
// HostRouteSupported returns an error if the HCN version does not support Host Route policies.
154160
func HostRouteSupported() error {
155-
supported := GetSupportedFeatures()
161+
supported, err := GetCachedSupportedFeatures()
162+
if err != nil {
163+
return err
164+
}
156165
if supported.HostRoute {
157166
return nil
158167
}
@@ -161,7 +170,10 @@ func HostRouteSupported() error {
161170

162171
// DSRSupported returns an error if the HCN version does not support Direct Server Return.
163172
func DSRSupported() error {
164-
supported := GetSupportedFeatures()
173+
supported, err := GetCachedSupportedFeatures()
174+
if err != nil {
175+
return err
176+
}
165177
if supported.DSR {
166178
return nil
167179
}
@@ -170,7 +182,10 @@ func DSRSupported() error {
170182

171183
// Slash32EndpointPrefixesSupported returns an error if the HCN version does not support configuring endpoints with /32 prefixes.
172184
func Slash32EndpointPrefixesSupported() error {
173-
supported := GetSupportedFeatures()
185+
supported, err := GetCachedSupportedFeatures()
186+
if err != nil {
187+
return err
188+
}
174189
if supported.Slash32EndpointPrefixes {
175190
return nil
176191
}
@@ -179,7 +194,10 @@ func Slash32EndpointPrefixesSupported() error {
179194

180195
// AclSupportForProtocol252Supported returns an error if the HCN version does not support HNS ACL Policies to support protocol 252 for VXLAN.
181196
func AclSupportForProtocol252Supported() error {
182-
supported := GetSupportedFeatures()
197+
supported, err := GetCachedSupportedFeatures()
198+
if err != nil {
199+
return err
200+
}
183201
if supported.AclSupportForProtocol252 {
184202
return nil
185203
}
@@ -188,7 +206,10 @@ func AclSupportForProtocol252Supported() error {
188206

189207
// SessionAffinitySupported returns an error if the HCN version does not support Session Affinity.
190208
func SessionAffinitySupported() error {
191-
supported := GetSupportedFeatures()
209+
supported, err := GetCachedSupportedFeatures()
210+
if err != nil {
211+
return err
212+
}
192213
if supported.SessionAffinity {
193214
return nil
194215
}
@@ -197,7 +218,10 @@ func SessionAffinitySupported() error {
197218

198219
// IPv6DualStackSupported returns an error if the HCN version does not support IPv6DualStack.
199220
func IPv6DualStackSupported() error {
200-
supported := GetSupportedFeatures()
221+
supported, err := GetCachedSupportedFeatures()
222+
if err != nil {
223+
return err
224+
}
201225
if supported.IPv6DualStack {
202226
return nil
203227
}
@@ -206,7 +230,10 @@ func IPv6DualStackSupported() error {
206230

207231
//L4proxySupported returns an error if the HCN verison does not support L4Proxy
208232
func L4proxyPolicySupported() error {
209-
supported := GetSupportedFeatures()
233+
supported, err := GetCachedSupportedFeatures()
234+
if err != nil {
235+
return err
236+
}
210237
if supported.L4Proxy {
211238
return nil
212239
}
@@ -215,7 +242,10 @@ func L4proxyPolicySupported() error {
215242

216243
// L4WfpProxySupported returns an error if the HCN verison does not support L4WfpProxy
217244
func L4WfpProxyPolicySupported() error {
218-
supported := GetSupportedFeatures()
245+
supported, err := GetCachedSupportedFeatures()
246+
if err != nil {
247+
return err
248+
}
219249
if supported.L4WfpProxy {
220250
return nil
221251
}
@@ -224,7 +254,10 @@ func L4WfpProxyPolicySupported() error {
224254

225255
// SetPolicySupported returns an error if the HCN version does not support SetPolicy.
226256
func SetPolicySupported() error {
227-
supported := GetSupportedFeatures()
257+
supported, err := GetCachedSupportedFeatures()
258+
if err != nil {
259+
return err
260+
}
228261
if supported.SetPolicy {
229262
return nil
230263
}
@@ -233,7 +266,10 @@ func SetPolicySupported() error {
233266

234267
// VxlanPortSupported returns an error if the HCN version does not support configuring the VXLAN TCP port.
235268
func VxlanPortSupported() error {
236-
supported := GetSupportedFeatures()
269+
supported, err := GetCachedSupportedFeatures()
270+
if err != nil {
271+
return err
272+
}
237273
if supported.VxlanPort {
238274
return nil
239275
}
@@ -242,7 +278,10 @@ func VxlanPortSupported() error {
242278

243279
// TierAclPolicySupported returns an error if the HCN version does not support configuring the TierAcl.
244280
func TierAclPolicySupported() error {
245-
supported := GetSupportedFeatures()
281+
supported, err := GetCachedSupportedFeatures()
282+
if err != nil {
283+
return err
284+
}
246285
if supported.TierAcl {
247286
return nil
248287
}
@@ -251,7 +290,10 @@ func TierAclPolicySupported() error {
251290

252291
// NetworkACLPolicySupported returns an error if the HCN version does not support NetworkACLPolicy
253292
func NetworkACLPolicySupported() error {
254-
supported := GetSupportedFeatures()
293+
supported, err := GetCachedSupportedFeatures()
294+
if err != nil {
295+
return err
296+
}
255297
if supported.NetworkACL {
256298
return nil
257299
}
@@ -260,14 +302,16 @@ func NetworkACLPolicySupported() error {
260302

261303
// NestedIpSetSupported returns an error if the HCN version does not support NestedIpSet
262304
func NestedIpSetSupported() error {
263-
supported := GetSupportedFeatures()
305+
supported, err := GetCachedSupportedFeatures()
306+
if err != nil {
307+
return err
308+
}
264309
if supported.NestedIpSet {
265310
return nil
266311
}
267312
return platformDoesNotSupportError("NestedIpSet")
268313
}
269314

270-
271315
// RequestType are the different operations performed to settings.
272316
// Used to update the settings of Endpoint/Namespace objects.
273317
type RequestType string

hcn/hcnsupport.go

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@ import (
44
"fmt"
55
"sync"
66

7+
"github.com/pkg/errors"
78
"github.com/sirupsen/logrus"
89
)
910

10-
var versionOnce sync.Once
11+
var (
12+
// featuresOnce handles assigning the supported features and printing the supported info to stdout only once to avoid unnecessary work
13+
// multiple times.
14+
featuresOnce sync.Once
15+
versionErr error
16+
supportedFeatures SupportedFeatures
17+
)
1118

1219
// SupportedFeatures are the features provided by the Service.
1320
type SupportedFeatures struct {
@@ -43,7 +50,59 @@ type ApiSupport struct {
4350
V2 bool `json:"V2"`
4451
}
4552

46-
// GetSupportedFeatures returns the features supported by the Service.
53+
// GetCachedSupportedFeatures returns the features supported by the Service and an error if the query failed. If this has been called
54+
// before it will return the supported features and error received from the first call. This can be used to optimize if many calls to the
55+
// various hcn.IsXSupported methods need to be made.
56+
func GetCachedSupportedFeatures() (SupportedFeatures, error) {
57+
// Only query the HCN version and features supported once, instead of everytime this is invoked. The logs are useful to
58+
// debug incidents where there's confusion on if a feature is supported on the host machine. The sync.Once helps to avoid redundant
59+
// spam of these anytime a check needs to be made for if an HCN feature is supported. This is a common occurrence in kube-proxy
60+
// for example.
61+
featuresOnce.Do(func() {
62+
globals, err := GetGlobals()
63+
if err != nil {
64+
// It's expected if this fails once, it should always fail. It should fail on pre 1803 builds for example.
65+
versionErr = errors.Wrap(err, "failed to query HCN version number: this is expected on pre 1803 builds.")
66+
} else {
67+
supportedFeatures.Acl = AclFeatures{
68+
AclAddressLists: isFeatureSupported(globals.Version, HNSVersion1803),
69+
AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
70+
AclPortRanges: isFeatureSupported(globals.Version, HNSVersion1803),
71+
AclRuleId: isFeatureSupported(globals.Version, HNSVersion1803),
72+
}
73+
74+
supportedFeatures.Api = ApiSupport{
75+
V2: isFeatureSupported(globals.Version, V2ApiSupport),
76+
V1: true, // HNSCall is still available.
77+
}
78+
79+
supportedFeatures.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion)
80+
supportedFeatures.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion)
81+
supportedFeatures.DSR = isFeatureSupported(globals.Version, DSRVersion)
82+
supportedFeatures.Slash32EndpointPrefixes = isFeatureSupported(globals.Version, Slash32EndpointPrefixesVersion)
83+
supportedFeatures.AclSupportForProtocol252 = isFeatureSupported(globals.Version, AclSupportForProtocol252Version)
84+
supportedFeatures.SessionAffinity = isFeatureSupported(globals.Version, SessionAffinityVersion)
85+
supportedFeatures.IPv6DualStack = isFeatureSupported(globals.Version, IPv6DualStackVersion)
86+
supportedFeatures.SetPolicy = isFeatureSupported(globals.Version, SetPolicyVersion)
87+
supportedFeatures.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion)
88+
supportedFeatures.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion)
89+
supportedFeatures.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion)
90+
supportedFeatures.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
91+
supportedFeatures.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
92+
supportedFeatures.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)
93+
94+
logrus.WithFields(logrus.Fields{
95+
"version": fmt.Sprintf("%+v", globals.Version),
96+
"supportedFeatures": fmt.Sprintf("%+v", supportedFeatures),
97+
}).Info("HCN feature check")
98+
}
99+
})
100+
101+
return supportedFeatures, versionErr
102+
}
103+
104+
// GetSupportedFeatures returns the features supported by the Service. Prefer `GetCachedSupportedFeatures` as this method will query hns and validate
105+
// every feature is supported on every invocation.
47106
func GetSupportedFeatures() SupportedFeatures {
48107
var features SupportedFeatures
49108

@@ -81,16 +140,10 @@ func GetSupportedFeatures() SupportedFeatures {
81140
features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
82141
features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)
83142

84-
// Only print the HCN version and features supported once, instead of everytime this is invoked. These logs are useful to
85-
// debug incidents where there's confusion on if a feature is supported on the host machine. The sync.Once helps to avoid redundant
86-
// spam of these anytime a check needs to be made for if an HCN feature is supported. This is a common occurrence in kubeproxy
87-
// for example.
88-
versionOnce.Do(func() {
89-
logrus.WithFields(logrus.Fields{
90-
"version": fmt.Sprintf("%+v", globals.Version),
91-
"supportedFeatures": fmt.Sprintf("%+v", features),
92-
}).Info("HCN feature check")
93-
})
143+
logrus.WithFields(logrus.Fields{
144+
"version": fmt.Sprintf("%+v", globals.Version),
145+
"supportedFeatures": fmt.Sprintf("%+v", features),
146+
}).Info("HCN feature check")
94147

95148
return features
96149
}

0 commit comments

Comments
 (0)