Skip to content

Commit eb9c641

Browse files
committed
Add "AppliedFixes" to HomeAzResponse
The NMAgent team has added an API version field to the HomeAZ response as a means to indicate whether or not certain bugfixes have been applied. Since this API Version field conveys no meaningful information, this adds an "AppliedFixes" field to the response to make it meaningful to users.
1 parent 4e356fc commit eb9c641

File tree

4 files changed

+203
-21
lines changed

4 files changed

+203
-21
lines changed

nmagent/client_test.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -756,18 +756,6 @@ func TestGetHomeAz(t *testing.T) {
756756
map[string]interface{}{
757757
"httpStatusCode": "200",
758758
"HomeAz": 1,
759-
"APIVersion": 0,
760-
},
761-
false,
762-
},
763-
{
764-
"happy path with new version",
765-
nmagent.AzResponse{HomeAz: uint(1), APIVersion: uint(2)},
766-
"/machine/plugins?comp=nmagent&type=GetHomeAz%2Fapi-version%2F1",
767-
map[string]interface{}{
768-
"httpStatusCode": "200",
769-
"HomeAz": 1,
770-
"APIVersion": 2,
771759
},
772760
false,
773761
},

nmagent/error.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ import (
1111
pkgerrors "github.com/pkg/errors"
1212
)
1313

14+
type HomeAzAPIVersionError struct {
15+
ReceivedAPIVersion uint
16+
}
17+
18+
func (h HomeAzAPIVersionError) Error() string {
19+
return fmt.Sprintf("invalid homeaz api version (must be 0 or 2): received %d", h.ReceivedAPIVersion)
20+
}
21+
1422
var deleteNetworkPattern = regexp.MustCompile(`/NetworkManagement/joinedVirtualNetworks/[^/]+/api-version/\d+/method/DELETE`)
1523

1624
// ContentError is encountered when an unexpected content type is obtained from

nmagent/responses.go

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package nmagent
22

3+
import (
4+
"encoding/json"
5+
6+
"github.com/pkg/errors"
7+
)
8+
39
type VirtualNetwork struct {
410
CNetSpace string `json:"cnetSpace"`
511
DefaultGateway string `json:"defaultGateway"`
@@ -37,20 +43,63 @@ type NCVersionList struct {
3743
Containers []NCVersion `json:"networkContainers"`
3844
}
3945

46+
// HomeAZFix is an indication that a particular bugfix has been applied to some
47+
// HomeAZ.
48+
type HomeAZFix int
49+
50+
const (
51+
HomeAZFixInvalid HomeAZFix = iota
52+
HomeAZFixIPv6
53+
)
54+
4055
type AzResponse struct {
41-
HomeAz uint `json:"homeAz"`
42-
APIVersion uint `json:"apiVersion"`
56+
HomeAz uint
57+
AppliedFixes []HomeAZFix
4358
}
4459

45-
func (az AzResponse) Valid() bool {
46-
// 0 should be valid when NMA version is old and does not have the apiVersion value in home az response
47-
//nolint:gomnd // these magic numbers are made by nma design
48-
return az.APIVersion == 0 || az.APIVersion == 2
60+
func (az *AzResponse) UnmarshalJSON(in []byte) error {
61+
type resp struct {
62+
HomeAz uint `json:"homeAz"`
63+
APIVersion uint `json:"apiVersion"`
64+
}
65+
66+
var rsp resp
67+
err := json.Unmarshal(in, &rsp)
68+
if err != nil {
69+
return errors.Wrap(err, "unmarshaling raw home az response")
70+
}
71+
72+
if rsp.APIVersion != 0 && rsp.APIVersion != 2 {
73+
return HomeAzAPIVersionError{
74+
ReceivedAPIVersion: rsp.APIVersion,
75+
}
76+
}
77+
78+
az.HomeAz = rsp.HomeAz
79+
80+
if rsp.APIVersion == 2 {
81+
az.AppliedFixes = append(az.AppliedFixes, HomeAZFixIPv6)
82+
}
83+
84+
return nil
4985
}
5086

51-
func (az AzResponse) NmaAppliedTheIPV6Fix() bool {
52-
//nolint:gomnd // this magic number is made by nma design
53-
return az.APIVersion >= 2
87+
// ContainsFixes reports whether all fixes requested are present in the
88+
// AzResponse returned.
89+
func (az AzResponse) ContainsFixes(requestedFixes ...HomeAZFix) bool {
90+
for _, requested := range requestedFixes {
91+
found := false
92+
for _, present := range az.AppliedFixes {
93+
if requested == present {
94+
found = true
95+
}
96+
}
97+
98+
if !found {
99+
return false
100+
}
101+
}
102+
return true
54103
}
55104

56105
type NodeIP struct {

nmagent/responses_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package nmagent_test
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/Azure/azure-container-networking/nmagent"
8+
"github.com/google/go-cmp/cmp"
9+
)
10+
11+
func TestContainsFixes(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
resp nmagent.AzResponse
15+
fixes []nmagent.HomeAZFix
16+
exp bool
17+
}{
18+
{
19+
"empty",
20+
nmagent.AzResponse{},
21+
[]nmagent.HomeAZFix{},
22+
true,
23+
},
24+
{
25+
"one present",
26+
nmagent.AzResponse{
27+
AppliedFixes: []nmagent.HomeAZFix{
28+
nmagent.HomeAZFixIPv6,
29+
},
30+
},
31+
[]nmagent.HomeAZFix{nmagent.HomeAZFixIPv6},
32+
true,
33+
},
34+
{
35+
"one absent",
36+
nmagent.AzResponse{
37+
AppliedFixes: []nmagent.HomeAZFix{},
38+
},
39+
[]nmagent.HomeAZFix{nmagent.HomeAZFixIPv6},
40+
false,
41+
},
42+
{
43+
"one with empty request",
44+
nmagent.AzResponse{
45+
AppliedFixes: []nmagent.HomeAZFix{
46+
nmagent.HomeAZFixIPv6,
47+
},
48+
},
49+
[]nmagent.HomeAZFix{},
50+
true,
51+
},
52+
}
53+
54+
for _, test := range tests {
55+
test := test
56+
t.Run(test.name, func(t *testing.T) {
57+
t.Parallel()
58+
got := test.resp.ContainsFixes(test.fixes...)
59+
60+
exp := test.exp
61+
if got != exp {
62+
t.Error("unexpected response from ContainsFixes: exp:", exp, "got:", got)
63+
}
64+
})
65+
}
66+
}
67+
68+
func TestUnmarshalAzResponse(t *testing.T) {
69+
tests := []struct {
70+
name string
71+
in string
72+
exp nmagent.AzResponse
73+
shouldErr bool
74+
}{
75+
{
76+
"empty",
77+
"{}",
78+
nmagent.AzResponse{},
79+
false,
80+
},
81+
{
82+
"only homeaz",
83+
`{"homeAz": 42}`,
84+
nmagent.AzResponse{
85+
HomeAz: 42,
86+
},
87+
false,
88+
},
89+
{
90+
"valid apiversion",
91+
`{"homeAz": 42, "apiVersion": 0}`,
92+
nmagent.AzResponse{
93+
HomeAz: 42,
94+
},
95+
false,
96+
},
97+
{
98+
"valid apiversion ipv6",
99+
`{"homeAz": 42, "apiVersion": 2}`,
100+
nmagent.AzResponse{
101+
HomeAz: 42,
102+
AppliedFixes: []nmagent.HomeAZFix{
103+
nmagent.HomeAZFixIPv6,
104+
},
105+
},
106+
false,
107+
},
108+
{
109+
"invalid apiversion",
110+
`{"homeAz": 42, "apiVersion": 42}`,
111+
nmagent.AzResponse{},
112+
true,
113+
},
114+
}
115+
116+
for _, test := range tests {
117+
test := test
118+
t.Run(test.name, func(t *testing.T) {
119+
t.Parallel()
120+
121+
var got nmagent.AzResponse
122+
err := json.Unmarshal([]byte(test.in), &got)
123+
if err != nil && !test.shouldErr {
124+
t.Fatal("unexpected error unmarshaling JSON: err:", err)
125+
}
126+
127+
if err == nil && test.shouldErr {
128+
t.Fatal("expected error but received none")
129+
}
130+
131+
exp := test.exp
132+
if !cmp.Equal(got, exp) {
133+
t.Error("received response differs from expected: diff:", cmp.Diff(got, exp))
134+
}
135+
})
136+
}
137+
}

0 commit comments

Comments
 (0)