Merge pull request #617 from thxCode/refactor_win_bridge

refactor(windows): win-bridge
This commit is contained in:
Dan Williams
2021-06-02 10:36:45 -05:00
committed by GitHub
8 changed files with 991 additions and 461 deletions

View File

@@ -24,6 +24,7 @@ import (
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
current "github.com/containernetworking/cni/pkg/types/100" current "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/errors" "github.com/containernetworking/plugins/pkg/errors"
) )
@@ -40,7 +41,7 @@ type EndpointInfo struct {
IpAddress net.IP IpAddress net.IP
} }
// GetSandboxContainerID returns the sandbox ID of this pod // GetSandboxContainerID returns the sandbox ID of this pod.
func GetSandboxContainerID(containerID string, netNs string) string { func GetSandboxContainerID(containerID string, netNs string) string {
if len(netNs) != 0 && netNs != pauseContainerNetNS { if len(netNs) != 0 && netNs != pauseContainerNetNS {
splits := strings.SplitN(netNs, ":", 2) splits := strings.SplitN(netNs, ":", 2)
@@ -52,7 +53,7 @@ func GetSandboxContainerID(containerID string, netNs string) string {
return containerID return containerID
} }
// short function so we know when to return "" for a string // GetIpString returns the given IP as a string.
func GetIpString(ip *net.IP) string { func GetIpString(ip *net.IP) string {
if len(*ip) == 0 { if len(*ip) == 0 {
return "" return ""
@@ -61,222 +62,136 @@ func GetIpString(ip *net.IP) string {
} }
} }
func GenerateHnsEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcsshim.HNSEndpoint, error) { // GetDefaultDestinationPrefix returns the default destination prefix according to the given IP type.
// run the IPAM plugin and get back the config to apply func GetDefaultDestinationPrefix(ip *net.IP) string {
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epInfo.EndpointName) destinationPrefix := "0.0.0.0/0"
if err != nil && !hcsshim.IsNotExist(err) { if ip.To4() == nil {
return nil, errors.Annotatef(err, "failed to get endpoint %q", epInfo.EndpointName) destinationPrefix = "::/0"
} }
return destinationPrefix
if hnsEndpoint != nil {
if hnsEndpoint.VirtualNetwork != epInfo.NetworkId {
_, err = hnsEndpoint.Delete()
if err != nil {
return nil, errors.Annotatef(err, "failed to delete endpoint %s", epInfo.EndpointName)
}
hnsEndpoint = nil
}
}
if n.LoopbackDSR {
n.ApplyLoopbackDSR(&epInfo.IpAddress)
}
if hnsEndpoint == nil {
hnsEndpoint = &hcsshim.HNSEndpoint{
Name: epInfo.EndpointName,
VirtualNetwork: epInfo.NetworkId,
DNSServerList: strings.Join(epInfo.DNS.Nameservers, ","),
DNSSuffix: strings.Join(epInfo.DNS.Search, ","),
GatewayAddress: GetIpString(&epInfo.Gateway),
IPAddress: epInfo.IpAddress,
Policies: n.MarshalPolicies(),
}
}
return hnsEndpoint, nil
} }
func GenerateHcnEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcn.HostComputeEndpoint, error) { // ConstructEndpointName constructs endpoint id which is used to identify an endpoint from HNS/HCN.
// run the IPAM plugin and get back the config to apply
hcnEndpoint, err := hcn.GetEndpointByName(epInfo.EndpointName)
if err != nil && !hcn.IsNotFoundError(err) {
return nil, errors.Annotatef(err, "failed to get endpoint %q", epInfo.EndpointName)
}
if hcnEndpoint != nil {
// If the endpont already exists, then we should return error unless
// the endpoint is based on a different network then delete
// should that fail return error
if !strings.EqualFold(hcnEndpoint.HostComputeNetwork, epInfo.NetworkId) {
err = hcnEndpoint.Delete()
if err != nil {
return nil, errors.Annotatef(err, "failed to delete endpoint %s", epInfo.EndpointName)
}
} else {
return nil, fmt.Errorf("endpoint %q already exits", epInfo.EndpointName)
}
}
if hcnEndpoint == nil {
routes := []hcn.Route{
{
NextHop: GetIpString(&epInfo.Gateway),
DestinationPrefix: GetDefaultDestinationPrefix(&epInfo.Gateway),
},
}
hcnDns := hcn.Dns{
Search: epInfo.DNS.Search,
ServerList: epInfo.DNS.Nameservers,
}
hcnIpConfig := hcn.IpConfig{
IpAddress: GetIpString(&epInfo.IpAddress),
}
ipConfigs := []hcn.IpConfig{hcnIpConfig}
if n.LoopbackDSR {
n.ApplyLoopbackDSR(&epInfo.IpAddress)
}
hcnEndpoint = &hcn.HostComputeEndpoint{
SchemaVersion: hcn.Version{Major: 2},
Name: epInfo.EndpointName,
HostComputeNetwork: epInfo.NetworkId,
Dns: hcnDns,
Routes: routes,
IpConfigurations: ipConfigs,
Policies: func() []hcn.EndpointPolicy {
if n.HcnPolicyArgs == nil {
n.HcnPolicyArgs = []hcn.EndpointPolicy{}
}
return n.HcnPolicyArgs
}(),
}
}
return hcnEndpoint, nil
}
// ConstructEndpointName constructs enpointId which is used to identify an endpoint from HNS
// There is a special consideration for netNs name here, which is required for Windows Server 1709
// containerID is the Id of the container on which the endpoint is worked on
func ConstructEndpointName(containerID string, netNs string, networkName string) string { func ConstructEndpointName(containerID string, netNs string, networkName string) string {
return GetSandboxContainerID(containerID, netNs) + "_" + networkName return GetSandboxContainerID(containerID, netNs) + "_" + networkName
} }
// DeprovisionEndpoint removes an endpoint from the container by sending a Detach request to HNS // GenerateHnsEndpoint generates an HNSEndpoint with given info and config.
// For shared endpoint, ContainerDetach is used func GenerateHnsEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcsshim.HNSEndpoint, error) {
// for removing the endpoint completely, HotDetachEndpoint is used // run the IPAM plugin and get back the config to apply
func DeprovisionEndpoint(epName string, netns string, containerID string) error { hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epInfo.EndpointName)
if err != nil && !hcsshim.IsNotExist(err) {
return nil, errors.Annotatef(err, "failed to get HNSEndpoint %s", epInfo.EndpointName)
}
if hnsEndpoint != nil {
if strings.EqualFold(hnsEndpoint.VirtualNetwork, epInfo.NetworkId) {
return nil, fmt.Errorf("HNSEndpoint %s is already existed", epInfo.EndpointName)
}
// remove endpoint if corrupted
if _, err = hnsEndpoint.Delete(); err != nil {
return nil, errors.Annotatef(err, "failed to delete corrupted HNSEndpoint %s", epInfo.EndpointName)
}
}
if n.LoopbackDSR {
n.ApplyLoopbackDSRPolicy(&epInfo.IpAddress)
}
hnsEndpoint = &hcsshim.HNSEndpoint{
Name: epInfo.EndpointName,
VirtualNetwork: epInfo.NetworkId,
DNSServerList: strings.Join(epInfo.DNS.Nameservers, ","),
DNSSuffix: strings.Join(epInfo.DNS.Search, ","),
GatewayAddress: GetIpString(&epInfo.Gateway),
IPAddress: epInfo.IpAddress,
Policies: n.GetHNSEndpointPolicies(),
}
return hnsEndpoint, nil
}
// RemoveHnsEndpoint detaches the given name endpoint from container specified by containerID,
// or removes the given name endpoint completely.
func RemoveHnsEndpoint(epName string, netns string, containerID string) error {
if len(netns) == 0 { if len(netns) == 0 {
return nil return nil
} }
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName) hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName)
if err != nil {
if hcsshim.IsNotExist(err) { if hcsshim.IsNotExist(err) {
return nil return nil
} else if err != nil { }
return errors.Annotatef(err, "failed to find HNSEndpoint %s", epName) return errors.Annotatef(err, "failed to find HNSEndpoint %s", epName)
} }
// for shared endpoint, detach it from the container
if netns != pauseContainerNetNS { if netns != pauseContainerNetNS {
// Shared endpoint removal. Do not remove the endpoint. _ = hnsEndpoint.ContainerDetach(containerID)
hnsEndpoint.ContainerDetach(containerID)
return nil return nil
} }
// Do not consider this as failure, else this would leak endpoints // for removing the endpoint completely, hot detach is used at first
hcsshim.HotDetachEndpoint(containerID, hnsEndpoint.Id) _ = hcsshim.HotDetachEndpoint(containerID, hnsEndpoint.Id)
_, _ = hnsEndpoint.Delete()
// Do not return error
hnsEndpoint.Delete()
return nil return nil
} }
type EndpointMakerFunc func() (*hcsshim.HNSEndpoint, error) type HnsEndpointMakerFunc func() (*hcsshim.HNSEndpoint, error)
// ProvisionEndpoint provisions an endpoint to a container specified by containerID. // AddHnsEndpoint attaches an HNSEndpoint to a container specified by containerID.
// If an endpoint already exists, the endpoint is reused. func AddHnsEndpoint(epName string, expectedNetworkId string, containerID string, netns string, makeEndpoint HnsEndpointMakerFunc) (*hcsshim.HNSEndpoint, error) {
// This call is idempotent hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName)
func ProvisionEndpoint(epName string, expectedNetworkId string, containerID string, netns string, makeEndpoint EndpointMakerFunc) (*hcsshim.HNSEndpoint, error) { if err != nil {
// On the second add call we expect that the endpoint already exists. If it if !hcsshim.IsNotExist(err) {
// does not then we should return an error.
if netns != pauseContainerNetNS {
_, err := hcsshim.GetHNSEndpointByName(epName)
if err != nil {
return nil, errors.Annotatef(err, "failed to find HNSEndpoint %s", epName) return nil, errors.Annotatef(err, "failed to find HNSEndpoint %s", epName)
} }
} }
// check if endpoint already exists // for shared endpoint, we expect that the endpoint already exists
createEndpoint := true if netns != pauseContainerNetNS {
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(epName) if hnsEndpoint == nil {
if hnsEndpoint != nil && strings.EqualFold(hnsEndpoint.VirtualNetwork, expectedNetworkId) { return nil, errors.Annotatef(err, "failed to find HNSEndpoint %s", epName)
createEndpoint = false }
} }
if createEndpoint { // verify the existing endpoint is corrupted or not
if hnsEndpoint != nil { if hnsEndpoint != nil {
if _, err = hnsEndpoint.Delete(); err != nil { if !strings.EqualFold(hnsEndpoint.VirtualNetwork, expectedNetworkId) {
return nil, errors.Annotate(err, "failed to delete the stale HNSEndpoint") if _, err := hnsEndpoint.Delete(); err != nil {
return nil, errors.Annotatef(err, "failed to delete corrupted HNSEndpoint %s", epName)
} }
hnsEndpoint = nil
} }
}
// create endpoint if not found
var isNewEndpoint bool
if hnsEndpoint == nil {
if hnsEndpoint, err = makeEndpoint(); err != nil { if hnsEndpoint, err = makeEndpoint(); err != nil {
return nil, errors.Annotate(err, "failed to make a new HNSEndpoint") return nil, errors.Annotate(err, "failed to make a new HNSEndpoint")
} }
if hnsEndpoint, err = hnsEndpoint.Create(); err != nil { if hnsEndpoint, err = hnsEndpoint.Create(); err != nil {
return nil, errors.Annotate(err, "failed to create the new HNSEndpoint") return nil, errors.Annotate(err, "failed to create the new HNSEndpoint")
} }
isNewEndpoint = true
} }
// hot attach // attach to container
if err := hcsshim.HotAttachEndpoint(containerID, hnsEndpoint.Id); err != nil { if err := hcsshim.HotAttachEndpoint(containerID, hnsEndpoint.Id); err != nil {
if createEndpoint { if isNewEndpoint {
err := DeprovisionEndpoint(epName, netns, containerID) if err := RemoveHnsEndpoint(epName, netns, containerID); err != nil {
if err != nil { return nil, errors.Annotatef(err, "failed to remove the new HNSEndpoint %s after attaching container %s failure", hnsEndpoint.Id, containerID)
return nil, errors.Annotatef(err, "failed to Deprovsion after HotAttach failure")
} }
} } else if hcsshim.ErrComputeSystemDoesNotExist == err {
if hcsshim.ErrComputeSystemDoesNotExist == err {
return hnsEndpoint, nil return hnsEndpoint, nil
} }
return nil, err return nil, errors.Annotatef(err, "failed to attach container %s to HNSEndpoint %s", containerID, hnsEndpoint.Id)
} }
return hnsEndpoint, nil return hnsEndpoint, nil
} }
type HcnEndpointMakerFunc func() (*hcn.HostComputeEndpoint, error) // ConstructHnsResult constructs the CNI result for the HNSEndpoint.
func ConstructHnsResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEndpoint) (*current.Result, error) {
func AddHcnEndpoint(epName string, expectedNetworkId string, namespace string,
makeEndpoint HcnEndpointMakerFunc) (*hcn.HostComputeEndpoint, error) {
hcnEndpoint, err := makeEndpoint()
if err != nil {
return nil, errors.Annotate(err, "failed to make a new HNSEndpoint")
}
if hcnEndpoint, err = hcnEndpoint.Create(); err != nil {
return nil, errors.Annotate(err, "failed to create the new HNSEndpoint")
}
err = hcn.AddNamespaceEndpoint(namespace, hcnEndpoint.Id)
if err != nil {
err := RemoveHcnEndpoint(epName)
if err != nil {
return nil, errors.Annotatef(err, "failed to Remove Endpoint after AddNamespaceEndpoint failure")
}
return nil, errors.Annotate(err, "failed to Add endpoint to namespace")
}
return hcnEndpoint, nil
}
// ConstructResult constructs the CNI result for the endpoint
func ConstructResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEndpoint) (*current.Result, error) {
resultInterface := &current.Interface{ resultInterface := &current.Interface{
Name: hnsEndpoint.Name, Name: hnsEndpoint.Name,
Mac: hnsEndpoint.MacAddress, Mac: hnsEndpoint.MacAddress,
@@ -296,7 +211,7 @@ func ConstructResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEnd
CNIVersion: current.ImplementedSpecVersion, CNIVersion: current.ImplementedSpecVersion,
Interfaces: []*current.Interface{resultInterface}, Interfaces: []*current.Interface{resultInterface},
IPs: []*current.IPConfig{resultIPConfig}, IPs: []*current.IPConfig{resultIPConfig},
DNS: types.DNS{ DNS: types.DNS{
Search: strings.Split(hnsEndpoint.DNSSuffix, ","), Search: strings.Split(hnsEndpoint.DNSSuffix, ","),
Nameservers: strings.Split(hnsEndpoint.DNSServerList, ","), Nameservers: strings.Split(hnsEndpoint.DNSServerList, ","),
}, },
@@ -305,24 +220,121 @@ func ConstructResult(hnsNetwork *hcsshim.HNSNetwork, hnsEndpoint *hcsshim.HNSEnd
return result, nil return result, nil
} }
// This version follows the v2 workflow of removing the endpoint from the namespace and deleting it // GenerateHcnEndpoint generates a HostComputeEndpoint with given info and config.
func GenerateHcnEndpoint(epInfo *EndpointInfo, n *NetConf) (*hcn.HostComputeEndpoint, error) {
// run the IPAM plugin and get back the config to apply
hcnEndpoint, err := hcn.GetEndpointByName(epInfo.EndpointName)
if err != nil && !hcn.IsNotFoundError(err) {
return nil, errors.Annotatef(err, "failed to get HostComputeEndpoint %s", epInfo.EndpointName)
}
// verify the existing endpoint is corrupted or not
if hcnEndpoint != nil {
if strings.EqualFold(hcnEndpoint.HostComputeNetwork, epInfo.NetworkId) {
return nil, fmt.Errorf("HostComputeNetwork %s is already existed", epInfo.EndpointName)
}
// remove endpoint if corrupted
if err := hcnEndpoint.Delete(); err != nil {
return nil, errors.Annotatef(err, "failed to delete corrupted HostComputeEndpoint %s", epInfo.EndpointName)
}
}
if n.LoopbackDSR {
n.ApplyLoopbackDSRPolicy(&epInfo.IpAddress)
}
hcnEndpoint = &hcn.HostComputeEndpoint{
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
Name: epInfo.EndpointName,
HostComputeNetwork: epInfo.NetworkId,
Dns: hcn.Dns{
Domain: epInfo.DNS.Domain,
Search: epInfo.DNS.Search,
ServerList: epInfo.DNS.Nameservers,
Options: epInfo.DNS.Options,
},
Routes: []hcn.Route{
{
NextHop: GetIpString(&epInfo.Gateway),
DestinationPrefix: GetDefaultDestinationPrefix(&epInfo.Gateway),
},
},
IpConfigurations: []hcn.IpConfig{
{
IpAddress: GetIpString(&epInfo.IpAddress),
},
},
Policies: n.GetHostComputeEndpointPolicies(),
}
return hcnEndpoint, nil
}
// RemoveHcnEndpoint removes the given name endpoint from namespace.
func RemoveHcnEndpoint(epName string) error { func RemoveHcnEndpoint(epName string) error {
hcnEndpoint, err := hcn.GetEndpointByName(epName) hcnEndpoint, err := hcn.GetEndpointByName(epName)
if hcn.IsNotFoundError(err) { if err != nil {
return nil if hcn.IsNotFoundError(err) {
} else if err != nil { return nil
_ = fmt.Errorf("[win-cni] Failed to find endpoint %v, err:%v", epName, err)
return err
}
if hcnEndpoint != nil {
err = hcnEndpoint.Delete()
if err != nil {
return fmt.Errorf("[win-cni] Failed to delete endpoint %v, err:%v", epName, err)
} }
return errors.Annotatef(err, "failed to find HostComputeEndpoint %s", epName)
}
err = hcnEndpoint.Delete()
if err != nil {
return errors.Annotatef(err, "failed to remove HostComputeEndpoint %s", epName)
} }
return nil return nil
} }
type HcnEndpointMakerFunc func() (*hcn.HostComputeEndpoint, error)
// AddHcnEndpoint attaches a HostComputeEndpoint to the given namespace.
func AddHcnEndpoint(epName string, expectedNetworkId string, namespace string, makeEndpoint HcnEndpointMakerFunc) (*hcn.HostComputeEndpoint, error) {
hcnEndpoint, err := hcn.GetEndpointByName(epName)
if err != nil {
if !hcn.IsNotFoundError(err) {
return nil, errors.Annotatef(err, "failed to find HostComputeEndpoint %s", epName)
}
}
// verify the existing endpoint is corrupted or not
if hcnEndpoint != nil {
if !strings.EqualFold(hcnEndpoint.HostComputeNetwork, expectedNetworkId) {
if err := hcnEndpoint.Delete(); err != nil {
return nil, errors.Annotatef(err, "failed to delete corrupted HostComputeEndpoint %s", epName)
}
hcnEndpoint = nil
}
}
// create endpoint if not found
var isNewEndpoint bool
if hcnEndpoint == nil {
if hcnEndpoint, err = makeEndpoint(); err != nil {
return nil, errors.Annotate(err, "failed to make a new HostComputeEndpoint")
}
if hcnEndpoint, err = hcnEndpoint.Create(); err != nil {
return nil, errors.Annotate(err, "failed to create the new HostComputeEndpoint")
}
isNewEndpoint = true
}
// add to namespace
err = hcn.AddNamespaceEndpoint(namespace, hcnEndpoint.Id)
if err != nil {
if isNewEndpoint {
if err := RemoveHcnEndpoint(epName); err != nil {
return nil, errors.Annotatef(err, "failed to remove the new HostComputeEndpoint %s after adding HostComputeNamespace %s failure", epName, namespace)
}
}
return nil, errors.Annotatef(err, "failed to add HostComputeEndpoint %s to HostComputeNamespace %s", epName, namespace)
}
return hcnEndpoint, nil
}
// ConstructHcnResult constructs the CNI result for the HostComputeEndpoint.
func ConstructHcnResult(hcnNetwork *hcn.HostComputeNetwork, hcnEndpoint *hcn.HostComputeEndpoint) (*current.Result, error) { func ConstructHcnResult(hcnNetwork *hcn.HostComputeNetwork, hcnEndpoint *hcn.HostComputeEndpoint) (*current.Result, error) {
resultInterface := &current.Interface{ resultInterface := &current.Interface{
Name: hcnEndpoint.Name, Name: hcnEndpoint.Name,
@@ -344,9 +356,11 @@ func ConstructHcnResult(hcnNetwork *hcn.HostComputeNetwork, hcnEndpoint *hcn.Hos
CNIVersion: current.ImplementedSpecVersion, CNIVersion: current.ImplementedSpecVersion,
Interfaces: []*current.Interface{resultInterface}, Interfaces: []*current.Interface{resultInterface},
IPs: []*current.IPConfig{resultIPConfig}, IPs: []*current.IPConfig{resultIPConfig},
DNS: types.DNS{ DNS: types.DNS{
Search: hcnEndpoint.Dns.Search, Search: hcnEndpoint.Dns.Search,
Nameservers: hcnEndpoint.Dns.ServerList, Nameservers: hcnEndpoint.Dns.ServerList,
Options: hcnEndpoint.Dns.Options,
Domain: hcnEndpoint.Dns.Domain,
}, },
} }

View File

@@ -20,7 +20,7 @@ import (
"testing" "testing"
) )
func TestHns(t *testing.T) { func TestNetConf(t *testing.T) {
RegisterFailHandler(Fail) RegisterFailHandler(Fail)
RunSpecs(t, "HNS NetConf Suite") RunSpecs(t, "NetConf Suite")
} }

View File

@@ -17,9 +17,10 @@ package hns
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"net" "net"
"strconv"
"strings" "strings"
"github.com/Microsoft/hcsshim/hcn" "github.com/Microsoft/hcsshim/hcn"
@@ -30,16 +31,16 @@ import (
// NetConf is the CNI spec // NetConf is the CNI spec
type NetConf struct { type NetConf struct {
types.NetConf types.NetConf
// ApiVersion is either 1 or 2, which specifies which hns APIs to call // ApiVersion specifies the policies type of HNS or HCN, select one of [1, 2].
ApiVersion int `json:"ApiVersion"` // HNS is the v1 API, which is the default version and applies to dockershim.
// V2 Api Policies // HCN is the v2 API, which can leverage HostComputeNamespace and use in containerd.
HcnPolicyArgs []hcn.EndpointPolicy `json:"HcnPolicyArgs,omitempty"` ApiVersion int `json:"apiVersion,omitempty"`
// V1 Api Policies // Policies specifies the policy list for HNSEndpoint or HostComputeEndpoint.
Policies []policy `json:"policies,omitempty"` Policies []Policy `json:"policies,omitempty"`
// Options to be passed in by the runtime // RuntimeConfig represents the options to be passed in by the runtime.
RuntimeConfig RuntimeConfig `json:"runtimeConfig"` RuntimeConfig RuntimeConfig `json:"runtimeConfig"`
// If true, adds a policy to endpoints to support loopback direct server return // LoopbackDSR specifies whether to support loopback direct server return.
LoopbackDSR bool `json:"loopbackDSR"` LoopbackDSR bool `json:"loopbackDSR,omitempty"`
} }
type RuntimeDNS struct { type RuntimeDNS struct {
@@ -54,42 +55,67 @@ type PortMapEntry struct {
HostIP string `json:"hostIP,omitempty"` HostIP string `json:"hostIP,omitempty"`
} }
// constants of the supported Windows Socket protocol,
// ref to https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.protocoltype.
var protocolEnums = map[string]uint32{
"icmpv4": 1,
"igmp": 2,
"tcp": 6,
"udp": 17,
"icmpv6": 58,
}
func (p *PortMapEntry) GetProtocolEnum() (uint32, error) {
var u, err = strconv.ParseUint(p.Protocol, 0, 10)
if err != nil {
var pe, exist = protocolEnums[strings.ToLower(p.Protocol)]
if !exist {
return 0, errors.New("invalid protocol supplied to port mapping policy")
}
return pe, nil
}
return uint32(u), nil
}
type RuntimeConfig struct { type RuntimeConfig struct {
DNS RuntimeDNS `json:"dns"` DNS RuntimeDNS `json:"dns"`
PortMaps []PortMapEntry `json:"portMappings,omitempty"` PortMaps []PortMapEntry `json:"portMappings,omitempty"`
} }
type policy struct { type Policy struct {
Name string `json:"name"` Name string `json:"name"`
Value json.RawMessage `json:"value"` Value json.RawMessage `json:"value"`
} }
func GetDefaultDestinationPrefix(ip *net.IP) string { // GetHNSEndpointPolicies converts the configuration policies to HNSEndpoint policies.
destinationPrefix := "0.0.0.0/0" func (n *NetConf) GetHNSEndpointPolicies() []json.RawMessage {
if ipv6 := ip.To4(); ipv6 == nil { result := make([]json.RawMessage, 0, len(n.Policies))
destinationPrefix = "::/0" for _, p := range n.Policies {
if !strings.EqualFold(p.Name, "EndpointPolicy") {
continue
}
result = append(result, p.Value)
} }
return destinationPrefix return result
} }
func (n *NetConf) ApplyLoopbackDSR(ip *net.IP) { // GetHostComputeEndpointPolicies converts the configuration policies to HostComputeEndpoint policies.
value := fmt.Sprintf(`"Destinations" : ["%s"]`, ip.String()) func (n *NetConf) GetHostComputeEndpointPolicies() []hcn.EndpointPolicy {
if n.ApiVersion == 2 { result := make([]hcn.EndpointPolicy, 0, len(n.Policies))
hcnLoopbackRoute := hcn.EndpointPolicy{ for _, p := range n.Policies {
Type: "OutBoundNAT", if !strings.EqualFold(p.Name, "EndpointPolicy") {
Settings: []byte(fmt.Sprintf("{%s}", value)), continue
} }
n.HcnPolicyArgs = append(n.HcnPolicyArgs, hcnLoopbackRoute) var policy hcn.EndpointPolicy
} else { if err := json.Unmarshal(p.Value, &policy); err != nil {
hnsLoopbackRoute := policy{ continue
Name: "EndpointPolicy",
Value: []byte(fmt.Sprintf(`{"Type": "OutBoundNAT", %s}`, value)),
} }
n.Policies = append(n.Policies, hnsLoopbackRoute) result = append(result, policy)
} }
return result
} }
// If runtime dns values are there use that else use cni conf supplied dns // GetDNS returns the DNS values if they are there use that else use netconf supplied DNS.
func (n *NetConf) GetDNS() types.DNS { func (n *NetConf) GetDNS() types.DNS {
dnsResult := n.DNS dnsResult := n.DNS
if len(n.RuntimeConfig.DNS.Nameservers) > 0 { if len(n.RuntimeConfig.DNS.Nameservers) > 0 {
@@ -101,136 +127,222 @@ func (n *NetConf) GetDNS() types.DNS {
return dnsResult return dnsResult
} }
// MarshalPolicies converts the Endpoint policies in Policies // ApplyLoopbackDSRPolicy configures the given IP to support loopback DSR.
// to HNS specific policies as Json raw bytes func (n *NetConf) ApplyLoopbackDSRPolicy(ip *net.IP) {
func (n *NetConf) MarshalPolicies() []json.RawMessage { if err := hcn.DSRSupported(); err != nil || ip == nil {
if n.Policies == nil { return
n.Policies = make([]policy, 0)
} }
result := make([]json.RawMessage, 0, len(n.Policies)) toPolicyValue := func(addr string) json.RawMessage {
for _, p := range n.Policies { if n.ApiVersion == 2 {
return bprintf(`{"Type": "OutBoundNAT", "Settings": {"Destinations": ["%s"]}}`, addr)
}
return bprintf(`{"Type": "OutBoundNAT", "Destinations": ["%s"]}`, addr)
}
ipBytes := []byte(ip.String())
// find OutBoundNAT policy
for i := range n.Policies {
p := &n.Policies[i]
if !strings.EqualFold(p.Name, "EndpointPolicy") { if !strings.EqualFold(p.Name, "EndpointPolicy") {
continue continue
} }
result = append(result, p.Value) // filter OutBoundNAT policy
} typeValue, _ := jsonparser.GetUnsafeString(p.Value, "Type")
if typeValue != "OutBoundNAT" {
return result
}
// ApplyOutboundNatPolicy applies NAT Policy in VFP using HNS
// Simultaneously an exception is added for the network that has to be Nat'd
func (n *NetConf) ApplyOutboundNatPolicy(nwToNat string) {
if n.Policies == nil {
n.Policies = make([]policy, 0)
}
nwToNatBytes := []byte(nwToNat)
for i, p := range n.Policies {
if !strings.EqualFold(p.Name, "EndpointPolicy") {
continue continue
} }
typeValue, err := jsonparser.GetUnsafeString(p.Value, "Type") // parse destination address list
if err != nil || len(typeValue) == 0 { var (
destinationsValue []byte
dt jsonparser.ValueType
)
if n.ApiVersion == 2 {
destinationsValue, dt, _, _ = jsonparser.Get(p.Value, "Settings", "Destinations")
} else {
destinationsValue, dt, _, _ = jsonparser.Get(p.Value, "Destinations")
}
// skip if Destinations/DestinationList field is not found
if dt == jsonparser.NotExist {
continue continue
} }
if !strings.EqualFold(typeValue, "OutBoundNAT") { // return if found the given address
continue
}
exceptionListValue, dt, _, _ := jsonparser.Get(p.Value, "ExceptionList")
// OutBoundNAT must with ExceptionList, so don't need to judge jsonparser.NotExist
if dt == jsonparser.Array { if dt == jsonparser.Array {
buf := bytes.Buffer{} var found bool
buf.WriteString(`{"Type": "OutBoundNAT", "ExceptionList": [`) _, _ = jsonparser.ArrayEach(destinationsValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
jsonparser.ArrayEach(exceptionListValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
if dataType == jsonparser.String && len(value) != 0 { if dataType == jsonparser.String && len(value) != 0 {
if bytes.Compare(value, nwToNatBytes) != 0 { if bytes.Compare(value, ipBytes) == 0 {
buf.WriteByte('"') found = true
buf.Write(value)
buf.WriteByte('"')
buf.WriteByte(',')
} }
} }
}) })
if found {
buf.WriteString(`"` + nwToNat + `"]}`) return
n.Policies[i] = policy{
Name: "EndpointPolicy",
Value: buf.Bytes(),
}
} else {
n.Policies[i] = policy{
Name: "EndpointPolicy",
Value: []byte(`{"Type": "OutBoundNAT", "ExceptionList": ["` + nwToNat + `"]}`),
} }
} }
return
} }
// didn't find the policyArg, add it // or add a new OutBoundNAT if not found
n.Policies = append(n.Policies, policy{ n.Policies = append(n.Policies, Policy{
Name: "EndpointPolicy", Name: "EndpointPolicy",
Value: []byte(`{"Type": "OutBoundNAT", "ExceptionList": ["` + nwToNat + `"]}`), Value: toPolicyValue(ip.String()),
}) })
} }
// ApplyDefaultPAPolicy is used to configure a endpoint PA policy in HNS // ApplyOutboundNatPolicy applies the sNAT policy in HNS/HCN and configures the given CIDR as an exception.
func (n *NetConf) ApplyDefaultPAPolicy(paAddress string) { func (n *NetConf) ApplyOutboundNatPolicy(exceptionCIDR string) {
if n.Policies == nil { if exceptionCIDR == "" {
n.Policies = make([]policy, 0) return
} }
// if its already present, leave untouched toPolicyValue := func(cidr ...string) json.RawMessage {
for i, p := range n.Policies { if n.ApiVersion == 2 {
return bprintf(`{"Type": "OutBoundNAT", "Settings": {"Exceptions": ["%s"]}}`, strings.Join(cidr, `","`))
}
return bprintf(`{"Type": "OutBoundNAT", "ExceptionList": ["%s"]}`, strings.Join(cidr, `","`))
}
exceptionCIDRBytes := []byte(exceptionCIDR)
// find OutBoundNAT policy
for i := range n.Policies {
p := &n.Policies[i]
if !strings.EqualFold(p.Name, "EndpointPolicy") { if !strings.EqualFold(p.Name, "EndpointPolicy") {
continue continue
} }
paValue, dt, _, _ := jsonparser.Get(p.Value, "PA") // filter OutBoundNAT policy
typeValue, _ := jsonparser.GetUnsafeString(p.Value, "Type")
if typeValue != "OutBoundNAT" {
continue
}
// parse exception CIDR list
var (
exceptionsValue []byte
dt jsonparser.ValueType
)
if n.ApiVersion == 2 {
exceptionsValue, dt, _, _ = jsonparser.Get(p.Value, "Settings", "Exceptions")
} else {
exceptionsValue, dt, _, _ = jsonparser.Get(p.Value, "ExceptionList")
}
// skip if Exceptions/ExceptionList field is not found
if dt == jsonparser.NotExist { if dt == jsonparser.NotExist {
continue continue
} else if dt == jsonparser.String && len(paValue) != 0 {
// found it, don't override
return
} }
n.Policies[i] = policy{ // return if found the given CIDR
Name: "EndpointPolicy", if dt == jsonparser.Array {
Value: []byte(`{"Type": "PA", "PA": "` + paAddress + `"}`), var found bool
_, _ = jsonparser.ArrayEach(exceptionsValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
if dataType == jsonparser.String && len(value) != 0 {
if bytes.Compare(value, exceptionCIDRBytes) == 0 {
found = true
}
}
})
if found {
return
}
} }
return
} }
// didn't find the policyArg, add it // or add a new OutBoundNAT if not found
n.Policies = append(n.Policies, policy{ n.Policies = append(n.Policies, Policy{
Name: "EndpointPolicy", Name: "EndpointPolicy",
Value: []byte(`{"Type": "PA", "PA": "` + paAddress + `"}`), Value: toPolicyValue(exceptionCIDR),
}) })
} }
// ApplyPortMappingPolicy is used to configure HostPort<>ContainerPort mapping in HNS // ApplyDefaultPAPolicy applies an endpoint PA policy in HNS/HCN.
func (n *NetConf) ApplyPortMappingPolicy(portMappings []PortMapEntry) { func (n *NetConf) ApplyDefaultPAPolicy(address string) {
if portMappings == nil { if address == "" {
return return
} }
if n.Policies == nil { toPolicyValue := func(addr string) json.RawMessage {
n.Policies = make([]policy, 0) if n.ApiVersion == 2 {
return bprintf(`{"Type": "ProviderAddress", "Settings": {"ProviderAddress": "%s"}}`, addr)
}
return bprintf(`{"Type": "PA", "PA": "%s"}`, addr)
}
addressBytes := []byte(address)
// find ProviderAddress policy
for i := range n.Policies {
p := &n.Policies[i]
if !strings.EqualFold(p.Name, "EndpointPolicy") {
continue
}
// filter ProviderAddress policy
typeValue, _ := jsonparser.GetUnsafeString(p.Value, "Type")
if typeValue != "PA" && typeValue != "ProviderAddress" {
continue
}
// parse provider address
var (
paValue []byte
dt jsonparser.ValueType
)
if n.ApiVersion == 2 {
paValue, dt, _, _ = jsonparser.Get(p.Value, "Settings", "ProviderAddress")
} else {
paValue, dt, _, _ = jsonparser.Get(p.Value, "PA")
}
// skip if ProviderAddress/PA field is not found
if dt == jsonparser.NotExist {
continue
}
// return if found the given address
if dt == jsonparser.String && bytes.Compare(paValue, addressBytes) == 0 {
return
}
} }
for _, portMapping := range portMappings { // or add a new ProviderAddress if not found
n.Policies = append(n.Policies, policy{ n.Policies = append(n.Policies, Policy{
Name: "EndpointPolicy",
Value: toPolicyValue(address),
})
}
// ApplyPortMappingPolicy applies the host/container port mapping policies in HNS/HCN.
func (n *NetConf) ApplyPortMappingPolicy(portMappings []PortMapEntry) {
if len(portMappings) == 0 {
return
}
toPolicyValue := func(p *PortMapEntry) json.RawMessage {
if n.ApiVersion == 2 {
var protocolEnum, _ = p.GetProtocolEnum()
return bprintf(`{"Type": "PortMapping", "Settings": {"InternalPort": %d, "ExternalPort": %d, "Protocol": %d, "VIP": "%s"}}`, p.ContainerPort, p.HostPort, protocolEnum, p.HostIP)
}
return bprintf(`{"Type": "NAT", "InternalPort": %d, "ExternalPort": %d, "Protocol": "%s"}`, p.ContainerPort, p.HostPort, p.Protocol)
}
for i := range portMappings {
p := &portMappings[i]
// skip the invalid protocol mapping
if _, err := p.GetProtocolEnum(); err != nil {
continue
}
n.Policies = append(n.Policies, Policy{
Name: "EndpointPolicy", Name: "EndpointPolicy",
Value: []byte(fmt.Sprintf(`{"Type": "NAT", "InternalPort": %d, "ExternalPort": %d, "Protocol": "%s"}`, portMapping.ContainerPort, portMapping.HostPort, portMapping.Protocol)), Value: toPolicyValue(p),
}) })
} }
} }
// bprintf is similar to fmt.Sprintf and returns a byte array as result.
func bprintf(format string, a ...interface{}) []byte {
return []byte(fmt.Sprintf(format, a...))
}

View File

@@ -15,221 +15,585 @@ package hns
import ( import (
"encoding/json" "encoding/json"
"net"
"github.com/Microsoft/hcsshim/hcn"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("HNS NetConf", func() { var _ = Describe("NetConf", func() {
Describe("ApplyOutBoundNATPolicy", func() { Describe("ApplyLoopbackDSRPolicy", func() {
Context("when not set by user", func() { Context("via v1 api", func() {
It("sets it by adding a policy", func() { var n NetConf
BeforeEach(func() {
n = NetConf{}
})
// apply it It("filter out duplicated IP", func() {
n := NetConf{} // mock duplicated IP
n.ApplyOutboundNatPolicy("192.168.0.0/16") ip := net.ParseIP("172.16.0.12")
n.ApplyLoopbackDSRPolicy(&ip)
n.ApplyLoopbackDSRPolicy(&ip)
// only one policy
addlArgs := n.Policies addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1)) Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0] policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy")) Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{}) value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value) json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type")) Expect(value).Should(HaveKey("Type"))
Expect(value).Should(HaveKey("ExceptionList"))
Expect(value["Type"]).Should(Equal("OutBoundNAT")) Expect(value["Type"]).Should(Equal("OutBoundNAT"))
Expect(value).Should(HaveKey("Destinations"))
exceptionList := value["ExceptionList"].([]interface{}) // and only one item
Expect(exceptionList).Should(HaveLen(1)) destinationList := value["Destinations"].([]interface{})
Expect(exceptionList[0].(string)).Should(Equal("192.168.0.0/16")) 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() { Context("via v2 api", func() {
It("appends exceptions to the existing policy", func() { var n NetConf
// first set it BeforeEach(func() {
n := NetConf{} n = NetConf{ApiVersion: 2}
n.ApplyOutboundNatPolicy("192.168.0.0/16") })
// then attempt to update it It("filter out duplicated IP", func() {
n.ApplyOutboundNatPolicy("10.244.0.0/16") // 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 addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1)) Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0] policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy")) Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
var value map[string]interface{}
json.Unmarshal(policy.Value, &value) json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type")) Expect(value).Should(HaveKey("Type"))
Expect(value).Should(HaveKey("ExceptionList"))
Expect(value["Type"]).Should(Equal("OutBoundNAT")) 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{}) exceptionList := value["ExceptionList"].([]interface{})
Expect(exceptionList).Should(HaveLen(2)) Expect(exceptionList).Should(HaveLen(1))
Expect(exceptionList[0].(string)).Should(Equal("192.168.0.0/16")) Expect(exceptionList[0].(string)).Should(Equal("10.244.0.0/16"))
Expect(exceptionList[1].(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() { Describe("ApplyDefaultPAPolicy", func() {
Context("when not set by user", func() { Context("via v1 api", func() {
It("sets it by adding a policy", func() { var n NetConf
BeforeEach(func() {
n := NetConf{} 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("when set by user", func() { It("append different IP", func() {
It("does not override", func() { // mock different IP
n := NetConf{}
n.ApplyDefaultPAPolicy("192.168.0.1") n.ApplyDefaultPAPolicy("192.168.0.1")
n.ApplyDefaultPAPolicy("192.168.0.2") n.ApplyDefaultPAPolicy("192.168.0.2")
// will be two policies
addlArgs := n.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")) Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{}) value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value) json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type")) Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("PA")) Expect(value["Type"]).Should(Equal("PA"))
// compare with second item
paAddress := value["PA"].(string) paAddress := value["PA"].(string)
Expect(paAddress).Should(Equal("192.168.0.1")) Expect(paAddress).Should(Equal("192.168.0.2"))
Expect(paAddress).ShouldNot(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() { Describe("ApplyPortMappingPolicy", func() {
Context("when portMappings not activated", func() { Context("via v1 api", func() {
It("does nothing", func() { var n NetConf
n := NetConf{} BeforeEach(func() {
n = NetConf{}
})
It("nothing to do if input is empty", func() {
n.ApplyPortMappingPolicy(nil) n.ApplyPortMappingPolicy(nil)
Expect(n.Policies).Should(BeNil()) Expect(n.Policies).Should(BeNil())
n.ApplyPortMappingPolicy([]PortMapEntry{}) n.ApplyPortMappingPolicy([]PortMapEntry{})
Expect(n.Policies).Should(HaveLen(0)) Expect(n.Policies).Should(BeNil())
}) })
})
Context("when portMappings is activated", func() { It("create one NAT policy", func() {
It("creates NAT policies", func() { // mock different IP
n := NetConf{}
n.ApplyPortMappingPolicy([]PortMapEntry{ n.ApplyPortMappingPolicy([]PortMapEntry{
{ {
ContainerPort: 80, ContainerPort: 80,
HostPort: 8080, HostPort: 8080,
Protocol: "TCP", 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")) Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{}) value := make(map[string]interface{})
json.Unmarshal(policy.Value, &value) json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type")) Expect(value).Should(HaveKey("Type"))
Expect(value["Type"]).Should(Equal("NAT")) Expect(value["Type"]).Should(Equal("NAT"))
// compare all values
Expect(value).Should(HaveKey("InternalPort")) Expect(value).Should(HaveKey("InternalPort"))
Expect(value["InternalPort"]).Should(Equal(float64(80))) Expect(value["InternalPort"]).Should(Equal(float64(80)))
Expect(value).Should(HaveKey("ExternalPort")) Expect(value).Should(HaveKey("ExternalPort"))
Expect(value["ExternalPort"]).Should(Equal(float64(8080))) Expect(value["ExternalPort"]).Should(Equal(float64(8080)))
Expect(value).Should(HaveKey("Protocol")) Expect(value).Should(HaveKey("Protocol"))
Expect(value["Protocol"]).Should(Equal("TCP")) Expect(value["Protocol"]).Should(Equal("TCP"))
}) })
}) })
})
Describe("MarshalPolicies", func() { Context("via v2 api", func() {
Context("when not set by user", func() { var n NetConf
It("sets it by adding a policy", func() { BeforeEach(func() {
n = NetConf{ApiVersion: 2}
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("when set by user", func() { It("nothing to do if input is empty", func() {
It("appends exceptions to the existing policy", func() { n.ApplyPortMappingPolicy(nil)
// first set it Expect(n.Policies).Should(BeNil())
n := NetConf{}
n.ApplyOutboundNatPolicy("192.168.0.0/16")
// then attempt to update it n.ApplyPortMappingPolicy([]PortMapEntry{})
n.ApplyOutboundNatPolicy("10.244.0.0/16") 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 addlArgs := n.Policies
Expect(addlArgs).Should(HaveLen(1)) Expect(addlArgs).Should(HaveLen(1))
// normal type judgement
policy := addlArgs[0] policy := addlArgs[0]
Expect(policy.Name).Should(Equal("EndpointPolicy")) Expect(policy.Name).Should(Equal("EndpointPolicy"))
value := make(map[string]interface{})
var value map[string]interface{}
json.Unmarshal(policy.Value, &value) json.Unmarshal(policy.Value, &value)
Expect(value).Should(HaveKey("Type")) Expect(value).Should(HaveKey("Type"))
Expect(value).Should(HaveKey("ExceptionList")) Expect(value["Type"]).Should(Equal("PortMapping"))
Expect(value["Type"]).Should(Equal("OutBoundNAT")) Expect(value).Should(HaveKey("Settings"))
exceptionList := value["ExceptionList"].([]interface{}) // compare all values
Expect(exceptionList).Should(HaveLen(2)) settings := value["Settings"].(map[string]interface{})
Expect(exceptionList[0].(string)).Should(Equal("192.168.0.0/16")) Expect(settings).Should(HaveKey("InternalPort"))
Expect(exceptionList[1].(string)).Should(Equal("10.244.0.0/16")) 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"))
}) })
}) })
}) })

View File

@@ -0,0 +1,52 @@
{
"name":"cbr0",
"type":"flannel",
"delegate":{
"apiVersion":2,
"type":"win-bridge",
"dns":{
"nameservers":[
"11.0.0.10"
],
"search":[
"svc.cluster.local"
]
},
"policies":[
{
"name":"EndpointPolicy",
"value":{
"Type":"OutBoundNAT",
"Settings":{
"Exceptions":[
"192.168.0.0/16",
"11.0.0.0/8",
"10.137.196.0/23"
]
}
}
},
{
"name":"EndpointPolicy",
"value":{
"Type":"SDNRoute",
"Settings":{
"DestinationPrefix":"11.0.0.0/8",
"NeedEncap":true
}
}
},
{
"name":"EndpointPolicy",
"value":{
"Type":"SDNRoute",
"Settings":{
"DestinationPrefix":"10.137.198.27/32",
"NeedEncap":true
}
}
}
],
"loopbackDSR":true
}
}

View File

@@ -55,21 +55,22 @@ func loadNetConf(bytes []byte) (*NetConf, string, error) {
return n, n.CNIVersion, nil return n, n.CNIVersion, nil
} }
func ProcessEndpointArgs(args *skel.CmdArgs, n *NetConf) (*hns.EndpointInfo, error) { func processEndpointArgs(args *skel.CmdArgs, n *NetConf) (*hns.EndpointInfo, error) {
epInfo := new(hns.EndpointInfo) epInfo := new(hns.EndpointInfo)
epInfo.NetworkName = n.Name epInfo.NetworkName = n.Name
epInfo.EndpointName = hns.ConstructEndpointName(args.ContainerID, args.Netns, epInfo.NetworkName) epInfo.EndpointName = hns.ConstructEndpointName(args.ContainerID, args.Netns, epInfo.NetworkName)
// It's not necessary to have have an IPAM in windows as hns can provide IP/GW
// it's not necessary to have have an IPAM in windows as HNS can provide IP/GW
if n.IPAM.Type != "" { if n.IPAM.Type != "" {
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData) r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while ipam.ExecAdd") return nil, errors.Annotatef(err, "error while executing IPAM addition")
} }
// Convert whatever the IPAM result was into the current Result type // convert whatever the IPAM result was into the current result
result, err := current.NewResultFromResult(r) result, err := current.NewResultFromResult(r)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while NewResultFromResult") return nil, errors.Annotatef(err, "error while converting the result from IPAM addition")
} else { } else {
if len(result.IPs) == 0 { if len(result.IPs) == 0 {
return nil, fmt.Errorf("IPAM plugin return is missing IP config") return nil, fmt.Errorf("IPAM plugin return is missing IP config")
@@ -81,12 +82,11 @@ func ProcessEndpointArgs(args *skel.CmdArgs, n *NetConf) (*hns.EndpointInfo, err
epInfo.Gateway[len(epInfo.Gateway)-1] += 2 epInfo.Gateway[len(epInfo.Gateway)-1] += 2
} }
} }
// NAT based on the the configured cluster network
if len(n.IPMasqNetwork) != 0 {
n.ApplyOutboundNatPolicy(n.IPMasqNetwork)
}
// Add HostPort mapping if any present // configure sNAT exception
n.ApplyOutboundNatPolicy(n.IPMasqNetwork)
// add port mapping if any present
n.ApplyPortMappingPolicy(n.RuntimeConfig.PortMaps) n.ApplyPortMappingPolicy(n.RuntimeConfig.PortMaps)
epInfo.DNS = n.GetDNS() epInfo.DNS = n.GetDNS()
@@ -98,40 +98,37 @@ func cmdHnsAdd(args *skel.CmdArgs, n *NetConf) (*current.Result, error) {
networkName := n.Name networkName := n.Name
hnsNetwork, err := hcsshim.GetHNSNetworkByName(networkName) hnsNetwork, err := hcsshim.GetHNSNetworkByName(networkName)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while GETHNSNewtorkByName(%s)", networkName) return nil, errors.Annotatef(err, "error while getting network %v", networkName)
} }
if hnsNetwork == nil { if hnsNetwork == nil {
return nil, fmt.Errorf("network %v not found", networkName) return nil, fmt.Errorf("network %v is not found", networkName)
} }
if !strings.EqualFold(hnsNetwork.Type, "L2Bridge") && !strings.EqualFold(hnsNetwork.Type, "L2Tunnel") { if !strings.EqualFold(hnsNetwork.Type, "L2Bridge") && !strings.EqualFold(hnsNetwork.Type, "L2Tunnel") {
return nil, fmt.Errorf("network %v is of an unexpected type: %v", networkName, hnsNetwork.Type) return nil, fmt.Errorf("network %v is of unexpected type: %v", networkName, hnsNetwork.Type)
} }
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name) epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
hnsEndpoint, err := hns.ProvisionEndpoint(epName, hnsNetwork.Id, args.ContainerID, args.Netns, func() (*hcsshim.HNSEndpoint, error) { hnsEndpoint, err := hns.AddHnsEndpoint(epName, hnsNetwork.Id, args.ContainerID, args.Netns, func() (*hcsshim.HNSEndpoint, error) {
epInfo, err := ProcessEndpointArgs(args, n) epInfo, err := processEndpointArgs(args, n)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while ProcessEndpointArgs") return nil, errors.Annotate(err, "error while processing endpoint args")
} }
epInfo.NetworkId = hnsNetwork.Id epInfo.NetworkId = hnsNetwork.Id
hnsEndpoint, err := hns.GenerateHnsEndpoint(epInfo, &n.NetConf) hnsEndpoint, err := hns.GenerateHnsEndpoint(epInfo, &n.NetConf)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while GenerateHnsEndpoint") return nil, errors.Annotate(err, "error while generating HNSEndpoint")
} }
return hnsEndpoint, nil return hnsEndpoint, nil
}) })
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while ProvisionEndpoint(%v,%v,%v)", epName, hnsNetwork.Id, args.ContainerID) return nil, errors.Annotate(err, "error while adding HNSEndpoint")
} }
result, err := hns.ConstructResult(hnsNetwork, hnsEndpoint) result, err := hns.ConstructHnsResult(hnsNetwork, hnsEndpoint)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while constructResult") return nil, errors.Annotate(err, "error while constructing HNSEndpoint addition result")
} }
return result, nil return result, nil
} }
@@ -139,48 +136,44 @@ func cmdHcnAdd(args *skel.CmdArgs, n *NetConf) (*current.Result, error) {
networkName := n.Name networkName := n.Name
hcnNetwork, err := hcn.GetNetworkByName(networkName) hcnNetwork, err := hcn.GetNetworkByName(networkName)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while GetNetworkByName(%s)", networkName) return nil, errors.Annotatef(err, "error while getting network %v", networkName)
} }
if hcnNetwork == nil { if hcnNetwork == nil {
return nil, fmt.Errorf("network %v not found", networkName) return nil, fmt.Errorf("network %v is not found", networkName)
} }
if hcnNetwork.Type != hcn.L2Bridge && hcnNetwork.Type != hcn.L2Tunnel { if hcnNetwork.Type != hcn.L2Bridge && hcnNetwork.Type != hcn.L2Tunnel {
return nil, fmt.Errorf("network %v is of unexpected type: %v", networkName, hcnNetwork.Type) return nil, fmt.Errorf("network %v is of unexpected type: %v", networkName, hcnNetwork.Type)
} }
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name) epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
hcnEndpoint, err := hns.AddHcnEndpoint(epName, hcnNetwork.Id, args.Netns, func() (*hcn.HostComputeEndpoint, error) { hcnEndpoint, err := hns.AddHcnEndpoint(epName, hcnNetwork.Id, args.Netns, func() (*hcn.HostComputeEndpoint, error) {
epInfo, err := ProcessEndpointArgs(args, n) epInfo, err := processEndpointArgs(args, n)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while ProcessEndpointArgs") return nil, errors.Annotate(err, "error while processing endpoint args")
} }
epInfo.NetworkId = hcnNetwork.Id epInfo.NetworkId = hcnNetwork.Id
hcnEndpoint, err := hns.GenerateHcnEndpoint(epInfo, &n.NetConf) hcnEndpoint, err := hns.GenerateHcnEndpoint(epInfo, &n.NetConf)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while GenerateHcnEndpoint") return nil, errors.Annotate(err, "error while generating HostComputeEndpoint")
} }
return hcnEndpoint, nil return hcnEndpoint, nil
}) })
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while AddHcnEndpoint(%v,%v,%v)", epName, hcnNetwork.Id, args.Netns) return nil, errors.Annotate(err, "error while adding HostComputeEndpoint")
} }
result, err := hns.ConstructHcnResult(hcnNetwork, hcnEndpoint) result, err := hns.ConstructHcnResult(hcnNetwork, hcnEndpoint)
if err != nil { if err != nil {
return nil, errors.Annotatef(err, "error while ConstructHcnResult") return nil, errors.Annotate(err, "error while constructing HostComputeEndpoint addition result")
} }
return result, nil return result, nil
} }
func cmdAdd(args *skel.CmdArgs) error { func cmdAdd(args *skel.CmdArgs) error {
n, cniVersion, err := loadNetConf(args.StdinData) n, cniVersion, err := loadNetConf(args.StdinData)
if err != nil { if err != nil {
return errors.Annotate(err, "error while loadNetConf") return err
} }
var result *current.Result var result *current.Result
@@ -189,15 +182,11 @@ func cmdAdd(args *skel.CmdArgs) error {
} else { } else {
result, err = cmdHnsAdd(args, n) result, err = cmdHnsAdd(args, n)
} }
if err != nil { if err != nil {
ipam.ExecDel(n.IPAM.Type, args.StdinData) ipam.ExecDel(n.IPAM.Type, args.StdinData)
return errors.Annotate(err, "error while executing ADD command") return err
} }
if result == nil {
return fmt.Errorf("result for ADD not populated correctly")
}
return types.PrintResult(result, cniVersion) return types.PrintResult(result, cniVersion)
} }
@@ -216,9 +205,8 @@ func cmdDel(args *skel.CmdArgs) error {
if n.ApiVersion == 2 { if n.ApiVersion == 2 {
return hns.RemoveHcnEndpoint(epName) return hns.RemoveHcnEndpoint(epName)
} else {
return hns.DeprovisionEndpoint(epName, args.Netns, args.ContainerID)
} }
return hns.RemoveHnsEndpoint(epName, args.Netns, args.ContainerID)
} }
func cmdCheck(_ *skel.CmdArgs) error { func cmdCheck(_ *skel.CmdArgs) error {

View File

@@ -86,7 +86,7 @@ func cmdAdd(args *skel.CmdArgs) error {
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name) epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
hnsEndpoint, err := hns.ProvisionEndpoint(epName, hnsNetwork.Id, args.ContainerID, args.Netns, func() (*hcsshim.HNSEndpoint, error) { hnsEndpoint, err := hns.AddHnsEndpoint(epName, hnsNetwork.Id, args.ContainerID, args.Netns, func() (*hcsshim.HNSEndpoint, error) {
// run the IPAM plugin and get back the config to apply // run the IPAM plugin and get back the config to apply
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData) r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
if err != nil { if err != nil {
@@ -119,7 +119,7 @@ func cmdAdd(args *skel.CmdArgs) error {
result.DNS = n.GetDNS() result.DNS = n.GetDNS()
if n.LoopbackDSR { if n.LoopbackDSR {
n.ApplyLoopbackDSR(&ipAddr) n.ApplyLoopbackDSRPolicy(&ipAddr)
} }
hnsEndpoint := &hcsshim.HNSEndpoint{ hnsEndpoint := &hcsshim.HNSEndpoint{
Name: epName, Name: epName,
@@ -129,7 +129,7 @@ func cmdAdd(args *skel.CmdArgs) error {
GatewayAddress: gw, GatewayAddress: gw,
IPAddress: ipAddr, IPAddress: ipAddr,
MacAddress: macAddr, MacAddress: macAddr,
Policies: n.MarshalPolicies(), Policies: n.GetHNSEndpointPolicies(),
} }
return hnsEndpoint, nil return hnsEndpoint, nil
@@ -140,10 +140,10 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
}() }()
if err != nil { if err != nil {
return errors.Annotatef(err, "error while ProvisionEndpoint(%v,%v,%v)", epName, hnsNetwork.Id, args.ContainerID) return errors.Annotatef(err, "error while AddHnsEndpoint(%v,%v,%v)", epName, hnsNetwork.Id, args.ContainerID)
} }
result, err := hns.ConstructResult(hnsNetwork, hnsEndpoint) result, err := hns.ConstructHnsResult(hnsNetwork, hnsEndpoint)
if err != nil { if err != nil {
return errors.Annotatef(err, "error while constructResult") return errors.Annotatef(err, "error while constructResult")
} }
@@ -164,7 +164,7 @@ func cmdDel(args *skel.CmdArgs) error {
epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name) epName := hns.ConstructEndpointName(args.ContainerID, args.Netns, n.Name)
return hns.DeprovisionEndpoint(epName, args.Netns, args.ContainerID) return hns.RemoveHnsEndpoint(epName, args.Netns, args.ContainerID)
} }
func cmdCheck(_ *skel.CmdArgs) error { func cmdCheck(_ *skel.CmdArgs) error {