refactor(win-bridge): netconf

- support v2 api
- unify v1 and v2 api

BREAKING CHANGE:
- remove `HcnPolicyArgs` field
- merge `HcnPolicyArgs` into `Policies` field

Signed-off-by: thxcode <thxcode0824@gmail.com>
This commit is contained in:
thxcode
2021-04-19 19:46:33 +08:00
committed by thxCode
parent 9215e60986
commit 4b180a9d9c
8 changed files with 758 additions and 228 deletions

View File

@ -15,221 +15,585 @@ package hns
import (
"encoding/json"
"net"
"github.com/Microsoft/hcsshim/hcn"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("HNS NetConf", func() {
Describe("ApplyOutBoundNATPolicy", func() {
Context("when not set by user", func() {
It("sets it by adding a policy", func() {
var _ = Describe("NetConf", func() {
Describe("ApplyLoopbackDSRPolicy", func() {
Context("via v1 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{}
})
// apply it
n := NetConf{}
n.ApplyOutboundNatPolicy("192.168.0.0/16")
It("filter out duplicated IP", func() {
// mock duplicated IP
ip := net.ParseIP("172.16.0.12")
n.ApplyLoopbackDSRPolicy(&ip)
n.ApplyLoopbackDSRPolicy(&ip)
// only one policy
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value).Should(HaveKey("ExceptionList"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Destinations"))
exceptionList := value["ExceptionList"].([]interface{})
Expect(exceptionList).Should(HaveLen(1))
Expect(exceptionList[0].(string)).Should(Equal("192.168.0.0/16"))
// and only one item
destinationList := value["Destinations"].([]interface{})
Expect(destinationList).Should(HaveLen(1))
Expect(destinationList[0].(string)).Should(Equal("172.16.0.12"))
})
It("append different IP", func() {
// mock different IP
ip1 := net.ParseIP("172.16.0.12")
n.ApplyLoopbackDSRPolicy(&ip1)
ip2 := net.ParseIP("172.16.0.13")
n.ApplyLoopbackDSRPolicy(&ip2)
// will be two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[1] // pick second item
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Destinations"))
// only one item
destinationList := value["Destinations"].([]interface{})
Expect(destinationList).Should(HaveLen(1))
Expect(destinationList[0].(string)).Should(Equal("172.16.0.13"))
})
})
Context("when set by user", func() {
It("appends exceptions to the existing policy", func() {
// first set it
n := NetConf{}
n.ApplyOutboundNatPolicy("192.168.0.0/16")
Context("via v2 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{ApiVersion: 2}
})
// then attempt to update it
n.ApplyOutboundNatPolicy("10.244.0.0/16")
It("filter out duplicated IP", func() {
// mock duplicated IP
ip := net.ParseIP("172.16.0.12")
n.ApplyLoopbackDSRPolicy(&ip)
n.ApplyLoopbackDSRPolicy(&ip)
// it should be unchanged!
// only one policy
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
var value map[string]interface{}
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value).Should(HaveKey("ExceptionList"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Settings"))
// and only one item
settings := value["Settings"].(map[string]interface{})
destinationList := settings["Destinations"].([]interface{})
Expect(destinationList).Should(HaveLen(1))
Expect(destinationList[0].(string)).Should(Equal("172.16.0.12"))
})
It("append different IP", func() {
// mock different IP
ip1 := net.ParseIP("172.16.0.12")
n.ApplyLoopbackDSRPolicy(&ip1)
ip2 := net.ParseIP("172.16.0.13")
n.ApplyLoopbackDSRPolicy(&ip2)
// will be two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[1] // pick second item
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Settings"))
// only one item
settings := value["Settings"].(map[string]interface{})
destinationList := settings["Destinations"].([]interface{})
Expect(destinationList).Should(HaveLen(1))
Expect(destinationList[0].(string)).Should(Equal("172.16.0.13"))
})
})
})
Describe("ApplyOutBoundNATPolicy", func() {
Context("via v1 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{}
})
It("append different IP", func() {
// mock different IP
n.ApplyOutboundNatPolicy("192.168.0.0/16")
n.ApplyOutboundNatPolicy("10.244.0.0/16")
// will be two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[1] // pick second item
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("ExceptionList"))
// but get two items
exceptionList := value["ExceptionList"].([]interface{})
Expect(exceptionList).Should(HaveLen(2))
Expect(exceptionList[0].(string)).Should(Equal("192.168.0.0/16"))
Expect(exceptionList[1].(string)).Should(Equal("10.244.0.0/16"))
Expect(exceptionList).Should(HaveLen(1))
Expect(exceptionList[0].(string)).Should(Equal("10.244.0.0/16"))
})
It("append a new one if there is not an exception OutBoundNAT policy", func() {
// mock different OutBoundNAT routes
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: bprintf(`{"Type": "OutBoundNAT", "OtherList": []}`),
},
}
n.ApplyOutboundNatPolicy("10.244.0.0/16")
// has two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("OtherList"))
policy = addlArgs[1]
value = make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("ExceptionList"))
// only get one item
exceptionList := value["ExceptionList"].([]interface{})
Expect(exceptionList).Should(HaveLen(1))
Expect(exceptionList[0].(string)).Should(Equal("10.244.0.0/16"))
})
It("nothing to do if CIDR is blank", func() {
// mock different OutBoundNAT routes
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: bprintf(`{"Type": "OutBoundNAT", "ExceptionList": []}`),
},
}
n.ApplyOutboundNatPolicy("")
// only one policy
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("ExceptionList"))
// empty list
Expect(value["ExceptionList"]).ShouldNot(BeNil())
Expect(value["ExceptionList"]).Should(HaveLen(0))
})
})
Context("via v2 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{ApiVersion: 2}
})
It("append different IP", func() {
// mock different IP
n.ApplyOutboundNatPolicy("192.168.0.0/16")
n.ApplyOutboundNatPolicy("10.244.0.0/16")
// will be two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[1] // pick second item
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Settings"))
// but get two items
settings := value["Settings"].(map[string]interface{})
exceptionList := settings["Exceptions"].([]interface{})
Expect(exceptionList).Should(HaveLen(1))
Expect(exceptionList[0].(string)).Should(Equal("10.244.0.0/16"))
})
It("append a new one if there is not an exception OutBoundNAT policy", func() {
// mock different OutBoundNAT routes
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: bprintf(`{"Type": "OutBoundNAT", "Settings": {"Others": []}}`),
},
}
n.ApplyOutboundNatPolicy("10.244.0.0/16")
// has two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Settings"))
Expect(value["Settings"]).Should(HaveKey("Others"))
policy = addlArgs[1]
value = make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Settings"))
// only get one item
settings := value["Settings"].(map[string]interface{})
exceptionList := settings["Exceptions"].([]interface{})
Expect(exceptionList).Should(HaveLen(1))
Expect(exceptionList[0].(string)).Should(Equal("10.244.0.0/16"))
})
It("nothing to do if CIDR is blank", func() {
// mock different OutBoundNAT routes
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: bprintf(`{"Type": "OutBoundNAT", "Settings": {"Exceptions": []}}`),
},
}
n.ApplyOutboundNatPolicy("")
// only one policy
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Settings"))
// empty list
settings := value["Settings"].(map[string]interface{})
Expect(settings["Exceptions"]).ShouldNot(BeNil())
Expect(settings["Exceptions"]).Should(HaveLen(0))
})
})
})
Describe("ApplyDefaultPAPolicy", func() {
Context("when not set by user", func() {
It("sets it by adding a policy", func() {
n := NetConf{}
n.ApplyDefaultPAPolicy("192.168.0.1")
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("PA"))
paAddress := value["PA"].(string)
Expect(paAddress).Should(Equal("192.168.0.1"))
Context("via v1 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{}
})
})
Context("when set by user", func() {
It("does not override", func() {
n := NetConf{}
It("append different IP", func() {
// mock different IP
n.ApplyDefaultPAPolicy("192.168.0.1")
n.ApplyDefaultPAPolicy("192.168.0.2")
// will be two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
Expect(addlArgs).Should(HaveLen(2))
policy := addlArgs[0]
// normal type judgement
policy := addlArgs[1] // judge second item
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("PA"))
// compare with second item
paAddress := value["PA"].(string)
Expect(paAddress).Should(Equal("192.168.0.1"))
Expect(paAddress).ShouldNot(Equal("192.168.0.2"))
Expect(paAddress).Should(Equal("192.168.0.2"))
})
It("nothing to do if IP is blank", func() {
// mock different policy
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: bprintf(`{"Type": "OutBoundNAT", "Exceptions": ["192.168.0.0/16"]}`),
},
}
n.ApplyDefaultPAPolicy("")
// nothing
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
})
})
Context("via v2 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{ApiVersion: 2}
})
It("append different IP", func() {
// mock different IP
n.ApplyDefaultPAPolicy("192.168.0.1")
n.ApplyDefaultPAPolicy("192.168.0.2")
// will be two policies
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(2))
// normal type judgement
policy := addlArgs[1] // judge second item
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("ProviderAddress"))
Expect(value).Should(HaveKey("Settings"))
// compare with second item
settings := value["Settings"].(map[string]interface{})
paAddress := settings["ProviderAddress"].(string)
Expect(paAddress).Should(Equal("192.168.0.2"))
})
It("nothing to do if IP is blank", func() {
// mock different policy
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: bprintf(`{"Type": "OutBoundNAT", "Settings": {"Exceptions": ["192.168.0.0/16"]}}`),
},
}
n.ApplyDefaultPAPolicy("")
// nothing
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
})
})
})
Describe("ApplyPortMappingPolicy", func() {
Context("when portMappings not activated", func() {
It("does nothing", func() {
n := NetConf{}
Context("via v1 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{}
})
It("nothing to do if input is empty", func() {
n.ApplyPortMappingPolicy(nil)
Expect(n.Policies).Should(BeNil())
n.ApplyPortMappingPolicy([]PortMapEntry{})
Expect(n.Policies).Should(HaveLen(0))
Expect(n.Policies).Should(BeNil())
})
})
Context("when portMappings is activated", func() {
It("creates NAT policies", func() {
n := NetConf{}
It("create one NAT policy", func() {
// mock different IP
n.ApplyPortMappingPolicy([]PortMapEntry{
{
ContainerPort: 80,
HostPort: 8080,
Protocol: "TCP",
HostIP: "ignored",
HostIP: "192.168.1.2",
},
})
Expect(n.Policies).Should(HaveLen(1))
// only one item
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
policy := n.Policies[0]
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("NAT"))
// compare all values
Expect(value).Should(HaveKey("InternalPort"))
Expect(value["InternalPort"]).Should(Equal(float64(80)))
Expect(value).Should(HaveKey("ExternalPort"))
Expect(value["ExternalPort"]).Should(Equal(float64(8080)))
Expect(value).Should(HaveKey("Protocol"))
Expect(value["Protocol"]).Should(Equal("TCP"))
})
})
})
Describe("MarshalPolicies", func() {
Context("when not set by user", func() {
It("sets it by adding a policy", func() {
n := NetConf{
Policies: []policy{
{
Name: "EndpointPolicy",
Value: []byte(`{"someKey": "someValue"}`),
},
{
Name: "someOtherType",
Value: []byte(`{"someOtherKey": "someOtherValue"}`),
},
},
}
result := n.MarshalPolicies()
Expect(len(result)).To(Equal(1))
policy := make(map[string]interface{})
err := json.Unmarshal(result[0], &policy)
Expect(err).ToNot(HaveOccurred())
Expect(policy).Should(HaveKey("someKey"))
Expect(policy["someKey"]).To(Equal("someValue"))
Context("via v2 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{ApiVersion: 2}
})
})
Context("when set by user", func() {
It("appends exceptions to the existing policy", func() {
// first set it
n := NetConf{}
n.ApplyOutboundNatPolicy("192.168.0.0/16")
It("nothing to do if input is empty", func() {
n.ApplyPortMappingPolicy(nil)
Expect(n.Policies).Should(BeNil())
// then attempt to update it
n.ApplyOutboundNatPolicy("10.244.0.0/16")
n.ApplyPortMappingPolicy([]PortMapEntry{})
Expect(n.Policies).Should(BeNil())
})
// it should be unchanged!
It("creates one NAT policy", func() {
// mock different IP
n.ApplyPortMappingPolicy([]PortMapEntry{
{
ContainerPort: 80,
HostPort: 8080,
Protocol: "TCP",
HostIP: "192.168.1.2",
},
})
// only one item
addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy"))
var value map[string]interface{}
value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type"))
Expect(value).Should(HaveKey("ExceptionList"))
Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value["Type"]).Should(Equal("PortMapping"))
Expect(value).Should(HaveKey("Settings"))
exceptionList := value["ExceptionList"].([]interface{})
Expect(exceptionList).Should(HaveLen(2))
Expect(exceptionList[0].(string)).Should(Equal("192.168.0.0/16"))
Expect(exceptionList[1].(string)).Should(Equal("10.244.0.0/16"))
// compare all values
settings := value["Settings"].(map[string]interface{})
Expect(settings).Should(HaveKey("InternalPort"))
Expect(settings["InternalPort"]).Should(Equal(float64(80)))
Expect(settings).Should(HaveKey("ExternalPort"))
Expect(settings["ExternalPort"]).Should(Equal(float64(8080)))
Expect(settings).Should(HaveKey("Protocol"))
Expect(settings["Protocol"]).Should(Equal(float64(6)))
Expect(settings).Should(HaveKey("VIP"))
Expect(settings["VIP"]).Should(Equal("192.168.1.2"))
})
})
})
Describe("GetXEndpointPolicies", func() {
Context("via v1 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{}
})
It("GetHNSEndpointPolicies", func() {
// mock different policies
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: []byte(`{"Type": "OutBoundNAT", "ExceptionList": [ "192.168.1.2" ]}`),
},
{
Name: "someOtherType",
Value: []byte(`{"someOtherKey": "someOtherValue"}`),
},
}
// only one valid item
result := n.GetHNSEndpointPolicies()
Expect(len(result)).To(Equal(1))
// normal type judgement
policy := make(map[string]interface{})
err := json.Unmarshal(result[0], &policy)
Expect(err).ToNot(HaveOccurred())
Expect(policy).Should(HaveKey("Type"))
Expect(policy["Type"]).To(Equal("OutBoundNAT"))
Expect(policy).Should(HaveKey("ExceptionList"))
Expect(policy["ExceptionList"]).To(ContainElement("192.168.1.2"))
})
})
Context("via v2 api", func() {
var n NetConf
BeforeEach(func() {
n = NetConf{ApiVersion: 2}
})
It("GetHostComputeEndpointPolicies", func() {
// mock different policies
n.Policies = []Policy{
{
Name: "EndpointPolicy",
Value: []byte(`{"Type": "OutBoundNAT", "Settings": {"Exceptions": [ "192.168.1.2" ]}}`),
},
{
Name: "someOtherType",
Value: []byte(`{"someOtherKey": "someOtherValue"}`),
},
}
// only one valid item
result := n.GetHostComputeEndpointPolicies()
Expect(len(result)).To(Equal(1))
// normal type judgement
policy := result[0]
Expect(policy.Type).Should(Equal(hcn.OutBoundNAT))
settings := make(map[string]interface{})
err := json.Unmarshal(policy.Settings, &settings)
Expect(err).ToNot(HaveOccurred())
Expect(settings["Exceptions"]).To(ContainElement("192.168.1.2"))
})
})
})