Update winkernel proxy for overlay

pull/564/head
ksubrmnn 2019-01-11 14:46:46 -08:00
parent 164f79e2d4
commit b724bdb19a
6 changed files with 1665 additions and 182 deletions

View File

@ -1,8 +1,10 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"hnsV1.go",
"hnsV2.go",
"metrics.go", "metrics.go",
"proxier.go", "proxier.go",
], ],
@ -15,6 +17,7 @@ go_library(
"//pkg/api/v1/service:go_default_library", "//pkg/api/v1/service:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library", "//pkg/apis/core/v1/helper:go_default_library",
"//pkg/proxy:go_default_library", "//pkg/proxy:go_default_library",
"//pkg/proxy/apis/config:go_default_library",
"//pkg/proxy/healthcheck:go_default_library", "//pkg/proxy/healthcheck:go_default_library",
"//pkg/util/async:go_default_library", "//pkg/util/async:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library",
@ -23,6 +26,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library",
"//vendor/github.com/Microsoft/hcsshim:go_default_library", "//vendor/github.com/Microsoft/hcsshim:go_default_library",
"//vendor/github.com/Microsoft/hcsshim/hcn:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library", "//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/k8s.io/klog:go_default_library", "//vendor/k8s.io/klog:go_default_library",
], ],
@ -43,3 +47,22 @@ filegroup(
tags = ["automanaged"], tags = ["automanaged"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
go_test(
name = "go_default_test",
srcs = [
"hns_test.go",
"proxier_test.go",
],
embed = [":go_default_library"],
deps = select({
"@io_bazel_rules_go//go/platform:windows": [
"//pkg/proxy:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/github.com/Microsoft/hcsshim/hcn:go_default_library",
],
"//conditions:default": [],
}),
)

View File

@ -0,0 +1,225 @@
// +build windows
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package winkernel
import (
"encoding/json"
"fmt"
"github.com/Microsoft/hcsshim"
"k8s.io/klog"
"net"
"strings"
)
type HostNetworkService interface {
getNetworkByName(name string) (*hnsNetworkInfo, error)
getEndpointByID(id string) (*endpointsInfo, error)
getEndpointByIpAddress(ip string, networkName string) (*endpointsInfo, error)
createEndpoint(ep *endpointsInfo, networkName string) (*endpointsInfo, error)
deleteEndpoint(hnsID string) error
getLoadBalancer(endpoints []endpointsInfo, isILB bool, isDSR bool, sourceVip string, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*loadBalancerInfo, error)
deleteLoadBalancer(hnsID string) error
}
// V1 HNS API
type hnsV1 struct{}
func (hns hnsV1) getNetworkByName(name string) (*hnsNetworkInfo, error) {
hnsnetwork, err := hcsshim.GetHNSNetworkByName(name)
if err != nil {
klog.Errorf("%v", err)
return nil, err
}
return &hnsNetworkInfo{
id: hnsnetwork.Id,
name: hnsnetwork.Name,
networkType: hnsnetwork.Type,
}, nil
}
func (hns hnsV1) getEndpointByID(id string) (*endpointsInfo, error) {
hnsendpoint, err := hcsshim.GetHNSEndpointByID(id)
if err != nil {
klog.Errorf("%v", err)
return nil, err
}
return &endpointsInfo{
ip: hnsendpoint.IPAddress.String(),
isLocal: !hnsendpoint.IsRemoteEndpoint, //TODO: Change isLocal to isRemote
macAddress: hnsendpoint.MacAddress,
hnsID: hnsendpoint.Id,
hns: hns,
}, nil
}
func (hns hnsV1) getEndpointByIpAddress(ip string, networkName string) (*endpointsInfo, error) {
hnsnetwork, err := hcsshim.GetHNSNetworkByName(networkName)
if err != nil {
klog.Errorf("%v", err)
return nil, err
}
endpoints, err := hcsshim.HNSListEndpointRequest()
for _, endpoint := range endpoints {
equal := false
if endpoint.IPAddress != nil {
equal = endpoint.IPAddress.String() == ip
}
if equal && strings.EqualFold(endpoint.VirtualNetwork, hnsnetwork.Id) {
return &endpointsInfo{
ip: endpoint.IPAddress.String(),
isLocal: !endpoint.IsRemoteEndpoint,
macAddress: endpoint.MacAddress,
hnsID: endpoint.Id,
hns: hns,
}, nil
}
}
return nil, fmt.Errorf("Endpoint %v not found on network %s", ip, networkName)
}
func (hns hnsV1) createEndpoint(ep *endpointsInfo, networkName string) (*endpointsInfo, error) {
hnsNetwork, err := hcsshim.GetHNSNetworkByName(networkName)
if err != nil {
return nil, fmt.Errorf("Could not find network %s: %v", networkName, err)
}
hnsEndpoint := &hcsshim.HNSEndpoint{
MacAddress: ep.macAddress,
IPAddress: net.ParseIP(ep.ip),
}
var createdEndpoint *hcsshim.HNSEndpoint
if !ep.isLocal {
if len(ep.providerAddress) != 0 {
paPolicy := hcsshim.PaPolicy{
Type: hcsshim.PA,
PA: ep.providerAddress,
}
paPolicyJson, err := json.Marshal(paPolicy)
if err != nil {
return nil, fmt.Errorf("PA Policy creation failed: %v", err)
}
hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicyJson)
}
createdEndpoint, err = hnsNetwork.CreateRemoteEndpoint(hnsEndpoint)
if err != nil {
return nil, fmt.Errorf("Remote endpoint creation failed: %v", err)
}
} else {
createdEndpoint, err = hnsNetwork.CreateEndpoint(hnsEndpoint)
if err != nil {
return nil, fmt.Errorf("Local endpoint creation failed: %v", err)
}
}
return &endpointsInfo{
ip: createdEndpoint.IPAddress.String(),
isLocal: createdEndpoint.IsRemoteEndpoint,
macAddress: createdEndpoint.MacAddress,
hnsID: createdEndpoint.Id,
providerAddress: ep.providerAddress, //TODO get from createdEndpoint
hns: hns,
}, nil
}
func (hns hnsV1) deleteEndpoint(hnsID string) error {
hnsendpoint, err := hcsshim.GetHNSEndpointByID(hnsID)
if err != nil {
return err
}
_, err = hnsendpoint.Delete()
if err == nil {
klog.V(3).Infof("Remote endpoint resource deleted id %s", hnsID)
}
return err
}
func (hns hnsV1) getLoadBalancer(endpoints []endpointsInfo, isILB bool, isDSR bool, sourceVip string, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*loadBalancerInfo, error) {
plists, err := hcsshim.HNSListPolicyListRequest()
if err != nil {
return nil, err
}
if isDSR {
klog.V(3).Info("DSR is not supported in V1. Using non DSR instead")
}
for _, plist := range plists {
if len(plist.EndpointReferences) != len(endpoints) {
continue
}
// Validate if input meets any of the policy lists
elbPolicy := hcsshim.ELBPolicy{}
if err = json.Unmarshal(plist.Policies[0], &elbPolicy); err != nil {
continue
}
if elbPolicy.Protocol == protocol && elbPolicy.InternalPort == internalPort && elbPolicy.ExternalPort == externalPort && elbPolicy.ILB == isILB {
if len(vip) > 0 {
if len(elbPolicy.VIPs) == 0 || elbPolicy.VIPs[0] != vip {
continue
}
}
LogJson(plist, "Found existing Hns loadbalancer policy resource", 1)
return &loadBalancerInfo{
hnsID: plist.ID,
}, nil
}
}
var hnsEndpoints []hcsshim.HNSEndpoint
for _, ep := range endpoints {
endpoint, err := hcsshim.GetHNSEndpointByID(ep.hnsID)
if err != nil {
return nil, err
}
hnsEndpoints = append(hnsEndpoints, *endpoint)
}
lb, err := hcsshim.AddLoadBalancer(
hnsEndpoints,
isILB,
sourceVip,
vip,
protocol,
internalPort,
externalPort,
)
if err == nil {
LogJson(lb, "Hns loadbalancer policy resource", 1)
} else {
return nil, err
}
return &loadBalancerInfo{
hnsID: lb.ID,
}, err
}
func (hns hnsV1) deleteLoadBalancer(hnsID string) error {
if len(hnsID) == 0 {
// Return silently
return nil
}
// Cleanup HNS policies
hnsloadBalancer, err := hcsshim.GetPolicyListByID(hnsID)
if err != nil {
return err
}
LogJson(hnsloadBalancer, "Removing Policy", 2)
_, err = hnsloadBalancer.Delete()
return err
}

View File

@ -0,0 +1,239 @@
// +build windows
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package winkernel
import (
"encoding/json"
"fmt"
"github.com/Microsoft/hcsshim/hcn"
"k8s.io/klog"
"strings"
)
type hnsV2 struct{}
func (hns hnsV2) getNetworkByName(name string) (*hnsNetworkInfo, error) {
hnsnetwork, err := hcn.GetNetworkByName(name)
if err != nil {
klog.Errorf("%v", err)
return nil, err
}
var remoteSubnets []*remoteSubnetInfo
for _, policy := range hnsnetwork.Policies {
if policy.Type == hcn.RemoteSubnetRoute {
policySettings := hcn.RemoteSubnetRoutePolicySetting{}
err = json.Unmarshal(policy.Settings, &policySettings)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal Remote Subnet policy settings")
}
rs := &remoteSubnetInfo{
destinationPrefix: policySettings.DestinationPrefix,
isolationId: policySettings.IsolationId,
providerAddress: policySettings.ProviderAddress,
drMacAddress: policySettings.DistributedRouterMacAddress,
}
remoteSubnets = append(remoteSubnets, rs)
}
}
return &hnsNetworkInfo{
id: hnsnetwork.Id,
name: hnsnetwork.Name,
networkType: string(hnsnetwork.Type),
remoteSubnets: remoteSubnets,
}, nil
}
func (hns hnsV2) getEndpointByID(id string) (*endpointsInfo, error) {
hnsendpoint, err := hcn.GetEndpointByID(id)
if err != nil {
return nil, err
}
return &endpointsInfo{ //TODO: fill out PA
ip: hnsendpoint.IpConfigurations[0].IpAddress,
isLocal: uint32(hnsendpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0, //TODO: Change isLocal to isRemote
macAddress: hnsendpoint.MacAddress,
hnsID: hnsendpoint.Id,
hns: hns,
}, nil
}
func (hns hnsV2) getEndpointByIpAddress(ip string, networkName string) (*endpointsInfo, error) {
hnsnetwork, err := hcn.GetNetworkByName(networkName)
if err != nil {
klog.Errorf("%v", err)
return nil, err
}
endpoints, err := hcn.ListEndpoints()
for _, endpoint := range endpoints {
equal := false
if endpoint.IpConfigurations != nil && len(endpoint.IpConfigurations) > 0 {
equal = endpoint.IpConfigurations[0].IpAddress == ip
}
if equal && strings.EqualFold(endpoint.HostComputeNetwork, hnsnetwork.Id) {
return &endpointsInfo{
ip: endpoint.IpConfigurations[0].IpAddress,
isLocal: uint32(endpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0, //TODO: Change isLocal to isRemote
macAddress: endpoint.MacAddress,
hnsID: endpoint.Id,
hns: hns,
}, nil
}
}
return nil, fmt.Errorf("Endpoint %v not found on network %s", ip, networkName)
}
func (hns hnsV2) createEndpoint(ep *endpointsInfo, networkName string) (*endpointsInfo, error) {
hnsNetwork, err := hcn.GetNetworkByName(networkName)
if err != nil {
return nil, fmt.Errorf("Could not find network %s: %v", networkName, err)
}
var flags hcn.EndpointFlags
if !ep.isLocal {
flags |= hcn.EndpointFlagsRemoteEndpoint
}
ipConfig := &hcn.IpConfig{
IpAddress: ep.ip,
}
hnsEndpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: ep.macAddress,
Flags: flags,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
var createdEndpoint *hcn.HostComputeEndpoint
if !ep.isLocal {
if len(ep.providerAddress) != 0 {
policySettings := hcn.ProviderAddressEndpointPolicySetting{
ProviderAddress: ep.providerAddress,
}
policySettingsJson, err := json.Marshal(policySettings)
if err != nil {
return nil, fmt.Errorf("PA Policy creation failed: %v", err)
}
paPolicy := hcn.EndpointPolicy{
Type: hcn.NetworkProviderAddress,
Settings: policySettingsJson,
}
hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy)
}
createdEndpoint, err = hnsNetwork.CreateRemoteEndpoint(hnsEndpoint)
if err != nil {
return nil, fmt.Errorf("Remote endpoint creation failed: %v", err)
}
} else {
createdEndpoint, err = hnsNetwork.CreateEndpoint(hnsEndpoint)
if err != nil {
return nil, fmt.Errorf("Local endpoint creation failed: %v", err)
}
}
return &endpointsInfo{
ip: createdEndpoint.IpConfigurations[0].IpAddress,
isLocal: uint32(createdEndpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
macAddress: createdEndpoint.MacAddress,
hnsID: createdEndpoint.Id,
providerAddress: ep.providerAddress, //TODO get from createdEndpoint
hns: hns,
}, nil
}
func (hns hnsV2) deleteEndpoint(hnsID string) error {
hnsendpoint, err := hcn.GetEndpointByID(hnsID)
if err != nil {
return err
}
err = hnsendpoint.Delete()
if err == nil {
klog.V(3).Infof("Remote endpoint resource deleted id %s", hnsID)
}
return err
}
func (hns hnsV2) getLoadBalancer(endpoints []endpointsInfo, isILB bool, isDSR bool, sourceVip string, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*loadBalancerInfo, error) {
plists, err := hcn.ListLoadBalancers()
if err != nil {
return nil, err
}
for _, plist := range plists {
if len(plist.HostComputeEndpoints) != len(endpoints) {
continue
}
// Validate if input meets any of the policy lists
lbPortMapping := plist.PortMappings[0]
if lbPortMapping.Protocol == uint32(protocol) && lbPortMapping.InternalPort == internalPort && lbPortMapping.ExternalPort == externalPort && (lbPortMapping.Flags&1 != 0) == isILB {
if len(vip) > 0 {
if len(plist.FrontendVIPs) == 0 || plist.FrontendVIPs[0] != vip {
continue
}
}
LogJson(plist, "Found existing Hns loadbalancer policy resource", 1)
return &loadBalancerInfo{
hnsID: plist.Id,
}, nil
}
}
var hnsEndpoints []hcn.HostComputeEndpoint
for _, ep := range endpoints {
endpoint, err := hcn.GetEndpointByID(ep.hnsID)
if err != nil {
return nil, err
}
hnsEndpoints = append(hnsEndpoints, *endpoint)
}
vips := []string{}
if len(vip) > 0 {
vips = append(vips, vip)
}
lb, err := hcn.AddLoadBalancer(
hnsEndpoints,
isILB,
isDSR,
sourceVip,
vips,
protocol,
internalPort,
externalPort,
)
if err != nil {
return nil, err
}
LogJson(lb, "Hns loadbalancer policy resource", 1)
return &loadBalancerInfo{
hnsID: lb.Id,
}, err
}
func (hns hnsV2) deleteLoadBalancer(hnsID string) error {
lb, err := hcn.GetLoadBalancerByID(hnsID)
if err != nil {
// Return silently
return nil
}
err = lb.Delete()
return err
}

View File

@ -0,0 +1,557 @@
// +build windows
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package winkernel
import (
"encoding/json"
"github.com/Microsoft/hcsshim/hcn"
"strings"
"testing"
)
const sourceVip = "192.168.1.2"
const serviceVip = "11.0.0.1"
const addressPrefix = "192.168.1.0/24"
const gatewayAddress = "192.168.1.1"
const epMacAddress = "00-11-22-33-44-55"
const epIpAddress = "192.168.1.3"
const epIpAddressRemote = "192.168.2.3"
const epPaAddress = "10.0.0.3"
const protocol = 6
const internalPort = 80
const externalPort = 32440
func TestGetNetworkByName(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testGetNetworkByName(t, hnsV1)
testGetNetworkByName(t, hnsV2)
}
func TestGetEndpointByID(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testGetEndpointByID(t, hnsV1)
testGetEndpointByID(t, hnsV2)
}
func TestGetEndpointByIpAddress(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testGetEndpointByIpAddress(t, hnsV1)
testGetEndpointByIpAddress(t, hnsV2)
}
func TestCreateEndpointLocal(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testCreateEndpointLocal(t, hnsV1)
testCreateEndpointLocal(t, hnsV2)
}
func TestCreateEndpointRemotePA(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testCreateEndpointRemote(t, hnsV1, epPaAddress)
testCreateEndpointRemote(t, hnsV2, epPaAddress)
}
func TestCreateEndpointRemoteNoPA(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testCreateEndpointRemote(t, hnsV1, "")
testCreateEndpointRemote(t, hnsV2, "")
}
func TestDeleteEndpoint(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testDeleteEndpoint(t, hnsV1)
testDeleteEndpoint(t, hnsV2)
}
func TestGetLoadBalancerExisting(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testGetLoadBalancerExisting(t, hnsV1)
testGetLoadBalancerExisting(t, hnsV2)
}
func TestGetLoadBalancerNew(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testGetLoadBalancerNew(t, hnsV1)
testGetLoadBalancerNew(t, hnsV2)
}
func TestDeleteLoadBalancer(t *testing.T) {
hnsV1 := hnsV1{}
hnsV2 := hnsV2{}
testDeleteLoadBalancer(t, hnsV1)
testDeleteLoadBalancer(t, hnsV2)
}
func testGetNetworkByName(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
network, err := hns.getNetworkByName(Network.Name)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(network.id, Network.Id) {
t.Errorf("%v does not match %v", network.id, Network.Id)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testGetEndpointByID(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
ipConfig := &hcn.IpConfig{
IpAddress: epIpAddress,
}
Endpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: epMacAddress,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
Endpoint, err = Network.CreateEndpoint(Endpoint)
if err != nil {
t.Error(err)
}
endpoint, err := hns.getEndpointByID(Endpoint.Id)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(endpoint.hnsID, Endpoint.Id) {
t.Errorf("%v does not match %v", endpoint.hnsID, Endpoint.Id)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testGetEndpointByIpAddress(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
ipConfig := &hcn.IpConfig{
IpAddress: epIpAddress,
}
Endpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: epMacAddress,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
Endpoint, err = Network.CreateEndpoint(Endpoint)
if err != nil {
t.Error(err)
}
endpoint, err := hns.getEndpointByIpAddress(Endpoint.IpConfigurations[0].IpAddress, Network.Name)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(endpoint.hnsID, Endpoint.Id) {
t.Errorf("%v does not match %v", endpoint.hnsID, Endpoint.Id)
}
if endpoint.ip != Endpoint.IpConfigurations[0].IpAddress {
t.Errorf("%v does not match %v", endpoint.ip, Endpoint.IpConfigurations[0].IpAddress)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testCreateEndpointLocal(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
endpoint := &endpointsInfo{
ip: epIpAddress,
macAddress: epMacAddress,
isLocal: true,
}
endpoint, err = hns.createEndpoint(endpoint, Network.Name)
if err != nil {
t.Error(err)
}
Endpoint, err := hcn.GetEndpointByID(endpoint.hnsID)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(endpoint.hnsID, Endpoint.Id) {
t.Errorf("%v does not match %v", endpoint.hnsID, Endpoint.Id)
}
if endpoint.ip != Endpoint.IpConfigurations[0].IpAddress {
t.Errorf("%v does not match %v", endpoint.ip, Endpoint.IpConfigurations[0].IpAddress)
}
if endpoint.macAddress != Endpoint.MacAddress {
t.Errorf("%v does not match %v", endpoint.macAddress, Endpoint.MacAddress)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testCreateEndpointRemote(t *testing.T, hns HostNetworkService, providerAddress string) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
endpoint := &endpointsInfo{
ip: epIpAddressRemote,
macAddress: epMacAddress,
isLocal: false,
providerAddress: providerAddress,
}
endpoint, err = hns.createEndpoint(endpoint, Network.Name)
if err != nil {
t.Error(err)
}
Endpoint, err := hcn.GetEndpointByID(endpoint.hnsID)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(endpoint.hnsID, Endpoint.Id) {
t.Errorf("%v does not match %v", endpoint.hnsID, Endpoint.Id)
}
if endpoint.ip != Endpoint.IpConfigurations[0].IpAddress {
t.Errorf("%v does not match %v", endpoint.ip, Endpoint.IpConfigurations[0].IpAddress)
}
if endpoint.macAddress != Endpoint.MacAddress {
t.Errorf("%v does not match %v", endpoint.macAddress, Endpoint.MacAddress)
}
if len(providerAddress) != 0 && endpoint.providerAddress != epPaAddress {
t.Errorf("%v does not match %v", endpoint.providerAddress, providerAddress)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testDeleteEndpoint(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
ipConfig := &hcn.IpConfig{
IpAddress: epIpAddress,
}
Endpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: epMacAddress,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
Endpoint, err = Network.CreateEndpoint(Endpoint)
if err != nil {
t.Error(err)
}
err = hns.deleteEndpoint(Endpoint.Id)
if err != nil {
t.Error(err)
}
// Endpoint should no longer exist so this should fail
Endpoint, err = hcn.GetEndpointByID(Endpoint.Id)
if err == nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testGetLoadBalancerExisting(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
ipConfig := &hcn.IpConfig{
IpAddress: epIpAddress,
}
Endpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: epMacAddress,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
Endpoint, err = Network.CreateEndpoint(Endpoint)
if err != nil {
t.Error(err)
}
Endpoints := []hcn.HostComputeEndpoint{*Endpoint}
LoadBalancer, err := hcn.AddLoadBalancer(
Endpoints,
false,
false,
sourceVip,
[]string{serviceVip},
protocol,
internalPort,
externalPort,
)
if err != nil {
t.Error(err)
}
endpoint := &endpointsInfo{
ip: Endpoint.IpConfigurations[0].IpAddress,
hnsID: Endpoint.Id,
}
endpoints := []endpointsInfo{*endpoint}
lb, err := hns.getLoadBalancer(endpoints, false, false, sourceVip, serviceVip, protocol, internalPort, externalPort)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(lb.hnsID, LoadBalancer.Id) {
t.Errorf("%v does not match %v", lb.hnsID, LoadBalancer.Id)
}
err = LoadBalancer.Delete()
if err != nil {
t.Error(err)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testGetLoadBalancerNew(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
ipConfig := &hcn.IpConfig{
IpAddress: epIpAddress,
}
Endpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: epMacAddress,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
Endpoint, err = Network.CreateEndpoint(Endpoint)
if err != nil {
t.Error(err)
}
endpoint := &endpointsInfo{
ip: Endpoint.IpConfigurations[0].IpAddress,
hnsID: Endpoint.Id,
}
endpoints := []endpointsInfo{*endpoint}
lb, err := hns.getLoadBalancer(endpoints, false, false, sourceVip, serviceVip, protocol, internalPort, externalPort)
if err != nil {
t.Error(err)
}
LoadBalancer, err := hcn.GetLoadBalancerByID(lb.hnsID)
if err != nil {
t.Error(err)
}
if !strings.EqualFold(lb.hnsID, LoadBalancer.Id) {
t.Errorf("%v does not match %v", lb.hnsID, LoadBalancer.Id)
}
err = LoadBalancer.Delete()
if err != nil {
t.Error(err)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func testDeleteLoadBalancer(t *testing.T, hns HostNetworkService) {
Network, err := createTestNetwork()
if err != nil {
t.Error(err)
}
ipConfig := &hcn.IpConfig{
IpAddress: epIpAddress,
}
Endpoint := &hcn.HostComputeEndpoint{
IpConfigurations: []hcn.IpConfig{*ipConfig},
MacAddress: epMacAddress,
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
Endpoint, err = Network.CreateEndpoint(Endpoint)
if err != nil {
t.Error(err)
}
Endpoints := []hcn.HostComputeEndpoint{*Endpoint}
LoadBalancer, err := hcn.AddLoadBalancer(
Endpoints,
false,
false,
sourceVip,
[]string{serviceVip},
protocol,
internalPort,
externalPort,
)
if err != nil {
t.Error(err)
}
err = hns.deleteLoadBalancer(LoadBalancer.Id)
if err != nil {
t.Error(err)
}
// Load balancer should not longer exist
LoadBalancer, err = hcn.GetLoadBalancerByID(LoadBalancer.Id)
if err == nil {
t.Error(err)
}
err = Endpoint.Delete()
if err != nil {
t.Error(err)
}
err = Network.Delete()
if err != nil {
t.Error(err)
}
}
func createTestNetwork() (*hcn.HostComputeNetwork, error) {
network := &hcn.HostComputeNetwork{
Type: "Overlay",
Name: "TestOverlay",
MacPool: hcn.MacPool{
Ranges: []hcn.MacRange{
{
StartMacAddress: "00-15-5D-52-C0-00",
EndMacAddress: "00-15-5D-52-CF-FF",
},
},
},
Ipams: []hcn.Ipam{
{
Type: "Static",
Subnets: []hcn.Subnet{
{
IpAddressPrefix: addressPrefix,
Routes: []hcn.Route{
{
NextHop: gatewayAddress,
DestinationPrefix: "0.0.0.0/0",
},
},
},
},
},
},
SchemaVersion: hcn.SchemaVersion{
Major: 2,
Minor: 0,
},
}
vsid := &hcn.VsidPolicySetting{
IsolationId: 5000,
}
vsidJson, err := json.Marshal(vsid)
if err != nil {
return nil, err
}
sp := &hcn.SubnetPolicy{
Type: hcn.VSID,
}
sp.Settings = vsidJson
spJson, err := json.Marshal(sp)
if err != nil {
return nil, err
}
network.Ipams[0].Subnets[0].Policies = append(network.Ipams[0].Subnets[0].Policies, spJson)
return network.Create()
}

View File

@ -29,6 +29,8 @@ import (
"time" "time"
"github.com/Microsoft/hcsshim" "github.com/Microsoft/hcsshim"
"github.com/Microsoft/hcsshim/hcn"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"k8s.io/klog" "k8s.io/klog"
@ -40,6 +42,7 @@ import (
apiservice "k8s.io/kubernetes/pkg/api/v1/service" apiservice "k8s.io/kubernetes/pkg/api/v1/service"
"k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/proxy" "k8s.io/kubernetes/pkg/proxy"
"k8s.io/kubernetes/pkg/proxy/apis/config"
"k8s.io/kubernetes/pkg/proxy/healthcheck" "k8s.io/kubernetes/pkg/proxy/healthcheck"
"k8s.io/kubernetes/pkg/util/async" "k8s.io/kubernetes/pkg/util/async"
) )
@ -82,6 +85,10 @@ type loadBalancerIngressInfo struct {
hnsID string hnsID string
} }
type loadBalancerInfo struct {
hnsID string
}
// internal struct for string service information // internal struct for string service information
type serviceInfo struct { type serviceInfo struct {
clusterIP net.IP clusterIP net.IP
@ -100,11 +107,22 @@ type serviceInfo struct {
hnsID string hnsID string
nodePorthnsID string nodePorthnsID string
policyApplied bool policyApplied bool
remoteEndpoint *endpointsInfo
hns HostNetworkService
} }
type hnsNetworkInfo struct { type hnsNetworkInfo struct {
name string name string
id string id string
networkType string
remoteSubnets []*remoteSubnetInfo
}
type remoteSubnetInfo struct {
destinationPrefix string
isolationId uint16
providerAddress string
drMacAddress string
} }
func Log(v interface{}, message string, level klog.Level) { func Log(v interface{}, message string, level klog.Level) {
@ -120,12 +138,14 @@ func LogJson(v interface{}, message string, level klog.Level) {
// internal struct for endpoints information // internal struct for endpoints information
type endpointsInfo struct { type endpointsInfo struct {
ip string ip string
port uint16 port uint16
isLocal bool isLocal bool
macAddress string macAddress string
hnsID string hnsID string
refCount uint16 refCount uint16
providerAddress string
hns HostNetworkService
} }
//Uses mac prefix and IPv4 address to return a mac address //Uses mac prefix and IPv4 address to return a mac address
@ -139,7 +159,7 @@ func conjureMac(macPrefix string, ip net.IP) string {
return "02-11-22-33-44-55" return "02-11-22-33-44-55"
} }
func newEndpointInfo(ip string, port uint16, isLocal bool) *endpointsInfo { func newEndpointInfo(ip string, port uint16, isLocal bool, hns HostNetworkService) *endpointsInfo {
info := &endpointsInfo{ info := &endpointsInfo{
ip: ip, ip: ip,
port: port, port: port,
@ -147,6 +167,7 @@ func newEndpointInfo(ip string, port uint16, isLocal bool) *endpointsInfo {
macAddress: conjureMac("02-11", net.ParseIP(ip)), macAddress: conjureMac("02-11", net.ParseIP(ip)),
refCount: 0, refCount: 0,
hnsID: "", hnsID: "",
hns: hns,
} }
return info return info
@ -160,14 +181,17 @@ func (ep *endpointsInfo) Cleanup() {
// Remove only remote endpoints created by this service // Remove only remote endpoints created by this service
if ep.refCount <= 0 && !ep.isLocal { if ep.refCount <= 0 && !ep.isLocal {
klog.V(4).Infof("Removing endpoints for %v, since no one is referencing it", ep) klog.V(4).Infof("Removing endpoints for %v, since no one is referencing it", ep)
deleteHnsEndpoint(ep.hnsID) err := ep.hns.deleteEndpoint(ep.hnsID)
ep.hnsID = "" if err == nil {
ep.hnsID = ""
} else {
klog.Errorf("Endpoint deletion failed for %v: %v", ep.ip, err)
}
} }
} }
// returns a new serviceInfo struct // returns a new serviceInfo struct
func newServiceInfo(svcPortName proxy.ServicePortName, port *v1.ServicePort, service *v1.Service) *serviceInfo { func newServiceInfo(svcPortName proxy.ServicePortName, port *v1.ServicePort, service *v1.Service, hns HostNetworkService) *serviceInfo {
onlyNodeLocalEndpoints := false onlyNodeLocalEndpoints := false
if apiservice.RequestsOnlyLocalTraffic(service) { if apiservice.RequestsOnlyLocalTraffic(service) {
onlyNodeLocalEndpoints = true onlyNodeLocalEndpoints = true
@ -175,8 +199,7 @@ func newServiceInfo(svcPortName proxy.ServicePortName, port *v1.ServicePort, ser
// set default session sticky max age 180min=10800s // set default session sticky max age 180min=10800s
stickyMaxAgeSeconds := 10800 stickyMaxAgeSeconds := 10800
if service.Spec.SessionAffinity == v1.ServiceAffinityClientIP { if service.Spec.SessionAffinity == v1.ServiceAffinityClientIP && service.Spec.SessionAffinityConfig != nil {
// Kube-apiserver side guarantees SessionAffinityConfig won't be nil when session affinity type is ClientIP
stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds)
} }
info := &serviceInfo{ info := &serviceInfo{
@ -193,6 +216,7 @@ func newServiceInfo(svcPortName proxy.ServicePortName, port *v1.ServicePort, ser
stickyMaxAgeSeconds: stickyMaxAgeSeconds, stickyMaxAgeSeconds: stickyMaxAgeSeconds,
loadBalancerSourceRanges: make([]string, len(service.Spec.LoadBalancerSourceRanges)), loadBalancerSourceRanges: make([]string, len(service.Spec.LoadBalancerSourceRanges)),
onlyNodeLocalEndpoints: onlyNodeLocalEndpoints, onlyNodeLocalEndpoints: onlyNodeLocalEndpoints,
hns: hns,
} }
copy(info.loadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) copy(info.loadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges)
@ -256,17 +280,17 @@ func newEndpointsChangeMap(hostname string) endpointsChangeMap {
} }
} }
func (ecm *endpointsChangeMap) update(namespacedName *types.NamespacedName, previous, current *v1.Endpoints) bool { func (ecm *endpointsChangeMap) update(namespacedName *types.NamespacedName, previous, current *v1.Endpoints, hns HostNetworkService) bool {
ecm.lock.Lock() ecm.lock.Lock()
defer ecm.lock.Unlock() defer ecm.lock.Unlock()
change, exists := ecm.items[*namespacedName] change, exists := ecm.items[*namespacedName]
if !exists { if !exists {
change = &endpointsChange{} change = &endpointsChange{}
change.previous = endpointsToEndpointsMap(previous, ecm.hostname) change.previous = endpointsToEndpointsMap(previous, ecm.hostname, hns)
ecm.items[*namespacedName] = change ecm.items[*namespacedName] = change
} }
change.current = endpointsToEndpointsMap(current, ecm.hostname) change.current = endpointsToEndpointsMap(current, ecm.hostname, hns)
if reflect.DeepEqual(change.previous, change.current) { if reflect.DeepEqual(change.previous, change.current) {
delete(ecm.items, *namespacedName) delete(ecm.items, *namespacedName)
} }
@ -279,7 +303,7 @@ func newServiceChangeMap() serviceChangeMap {
} }
} }
func (scm *serviceChangeMap) update(namespacedName *types.NamespacedName, previous, current *v1.Service) bool { func (scm *serviceChangeMap) update(namespacedName *types.NamespacedName, previous, current *v1.Service, hns HostNetworkService) bool {
scm.lock.Lock() scm.lock.Lock()
defer scm.lock.Unlock() defer scm.lock.Unlock()
@ -287,10 +311,10 @@ func (scm *serviceChangeMap) update(namespacedName *types.NamespacedName, previo
if !exists { if !exists {
// Service is Added // Service is Added
change = &serviceChange{} change = &serviceChange{}
change.previous = serviceToServiceMap(previous) change.previous = serviceToServiceMap(previous, hns)
scm.items[*namespacedName] = change scm.items[*namespacedName] = change
} }
change.current = serviceToServiceMap(current) change.current = serviceToServiceMap(current, hns)
if reflect.DeepEqual(change.previous, change.current) { if reflect.DeepEqual(change.previous, change.current) {
delete(scm.items, *namespacedName) delete(scm.items, *namespacedName)
} }
@ -420,7 +444,11 @@ type Proxier struct {
// precomputing some number of those and cache for future reuse. // precomputing some number of those and cache for future reuse.
precomputedProbabilities []string precomputedProbabilities []string
network hnsNetworkInfo hns HostNetworkService
network hnsNetworkInfo
sourceVip string
hostMac string
isDSR bool
} }
type localPort struct { type localPort struct {
@ -465,6 +493,7 @@ func NewProxier(
nodeIP net.IP, nodeIP net.IP,
recorder record.EventRecorder, recorder record.EventRecorder,
healthzServer healthcheck.HealthzUpdater, healthzServer healthcheck.HealthzUpdater,
config config.KubeProxyWinkernelConfiguration,
) (*Proxier, error) { ) (*Proxier, error) {
masqueradeValue := 1 << uint(masqueradeBit) masqueradeValue := 1 << uint(masqueradeBit)
masqueradeMark := fmt.Sprintf("%#08x/%#08x", masqueradeValue, masqueradeValue) masqueradeMark := fmt.Sprintf("%#08x/%#08x", masqueradeValue, masqueradeValue)
@ -479,19 +508,75 @@ func NewProxier(
} }
healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps
var hns HostNetworkService
// TODO : Make this a param hns = hnsV1{}
hnsNetworkName := os.Getenv("KUBE_NETWORK") supportedFeatures := hcn.GetSupportedFeatures()
if len(hnsNetworkName) == 0 { if supportedFeatures.Api.V2 {
return nil, fmt.Errorf("Environment variable KUBE_NETWORK not initialized") hns = hnsV2{}
} }
hnsNetwork, err := getHnsNetworkInfo(hnsNetworkName)
hnsNetworkName := config.NetworkName
if len(hnsNetworkName) == 0 {
klog.V(3).Infof("network-name flag not set. Checking environment variable")
hnsNetworkName = os.Getenv("KUBE_NETWORK")
if len(hnsNetworkName) == 0 {
return nil, fmt.Errorf("Environment variable KUBE_NETWORK and network-flag not initialized")
}
}
hnsNetworkInfo, err := hns.getNetworkByName(hnsNetworkName)
if err != nil { if err != nil {
klog.Fatalf("Unable to find Hns Network specified by %s. Please check environment variable KUBE_NETWORK", hnsNetworkName) klog.Errorf("Unable to find Hns Network specified by %s. Please check environment variable KUBE_NETWORK or network-name flag", hnsNetworkName)
return nil, err
}
klog.V(1).Infof("Hns Network loaded with info = %v", hnsNetworkInfo)
isDSR := config.EnableDSR
err = hcn.DSRSupported()
if isDSR && err != nil {
return nil, err return nil, err
} }
klog.V(1).Infof("Hns Network loaded with info = %v", hnsNetwork) var sourceVip string
var hostMac string
if hnsNetworkInfo.networkType == "Overlay" {
err = hcn.RemoteSubnetSupported()
if err != nil {
return nil, err
}
sourceVip = config.SourceVip
if len(sourceVip) == 0 {
return nil, fmt.Errorf("source-vip flag not set")
}
interfaces, _ := net.Interfaces() //TODO create interfaces
for _, inter := range interfaces {
addresses, _ := inter.Addrs()
for _, addr := range addresses {
addrIP, _, _ := net.ParseCIDR(addr.String())
if addrIP.String() == nodeIP.String() {
klog.V(2).Infof("Host MAC address is %s", inter.HardwareAddr.String())
hostMac = inter.HardwareAddr.String()
}
}
}
if len(hostMac) == 0 {
return nil, fmt.Errorf("Could not find host mac address for %s", nodeIP)
}
existingSourceVip, _ := hns.getEndpointByIpAddress(sourceVip, hnsNetworkName)
if existingSourceVip == nil {
hnsEndpoint := &endpointsInfo{
ip: sourceVip,
isLocal: true,
macAddress: hostMac,
providerAddress: nodeIP.String(),
}
_, err = hns.createEndpoint(hnsEndpoint, hnsNetworkName)
if err != nil {
return nil, fmt.Errorf("Source Vip endpoint creation failed: %v", err)
}
}
}
proxier := &Proxier{ proxier := &Proxier{
portsMap: make(map[localPort]closeable), portsMap: make(map[localPort]closeable),
@ -507,7 +592,11 @@ func NewProxier(
recorder: recorder, recorder: recorder,
healthChecker: healthChecker, healthChecker: healthChecker,
healthzServer: healthzServer, healthzServer: healthzServer,
network: *hnsNetwork, hns: hns,
network: *hnsNetworkInfo,
sourceVip: sourceVip,
hostMac: hostMac,
isDSR: isDSR,
} }
burstSyncs := 2 burstSyncs := 2
@ -536,27 +625,30 @@ func (svcInfo *serviceInfo) cleanupAllPolicies(endpoints []*endpointsInfo) {
for _, ep := range endpoints { for _, ep := range endpoints {
ep.Cleanup() ep.Cleanup()
} }
if svcInfo.remoteEndpoint != nil {
svcInfo.remoteEndpoint.Cleanup()
}
svcInfo.policyApplied = false svcInfo.policyApplied = false
} }
func (svcInfo *serviceInfo) deleteAllHnsLoadBalancerPolicy() { func (svcInfo *serviceInfo) deleteAllHnsLoadBalancerPolicy() {
// Remove the Hns Policy corresponding to this service // Remove the Hns Policy corresponding to this service
deleteHnsLoadBalancerPolicy(svcInfo.hnsID) hns := svcInfo.hns
hns.deleteLoadBalancer(svcInfo.hnsID)
svcInfo.hnsID = "" svcInfo.hnsID = ""
deleteHnsLoadBalancerPolicy(svcInfo.nodePorthnsID) hns.deleteLoadBalancer(svcInfo.nodePorthnsID)
svcInfo.nodePorthnsID = "" svcInfo.nodePorthnsID = ""
for _, externalIp := range svcInfo.externalIPs { for _, externalIp := range svcInfo.externalIPs {
deleteHnsLoadBalancerPolicy(externalIp.hnsID) hns.deleteLoadBalancer(externalIp.hnsID)
externalIp.hnsID = "" externalIp.hnsID = ""
} }
for _, lbIngressIp := range svcInfo.loadBalancerIngressIPs { for _, lbIngressIp := range svcInfo.loadBalancerIngressIPs {
deleteHnsLoadBalancerPolicy(lbIngressIp.hnsID) hns.deleteLoadBalancer(lbIngressIp.hnsID)
lbIngressIp.hnsID = "" lbIngressIp.hnsID = ""
} }
} }
func deleteAllHnsLoadBalancerPolicy() { func deleteAllHnsLoadBalancerPolicy() {
@ -574,87 +666,6 @@ func deleteAllHnsLoadBalancerPolicy() {
} }
// getHnsLoadBalancer returns the LoadBalancer policy resource, if already found.
// If not, it would create one and return
func getHnsLoadBalancer(endpoints []hcsshim.HNSEndpoint, isILB bool, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*hcsshim.PolicyList, error) {
plists, err := hcsshim.HNSListPolicyListRequest()
if err != nil {
return nil, err
}
for _, plist := range plists {
if len(plist.EndpointReferences) != len(endpoints) {
continue
}
// Validate if input meets any of the policy lists
elbPolicy := hcsshim.ELBPolicy{}
if err = json.Unmarshal(plist.Policies[0], &elbPolicy); err != nil {
continue
}
if elbPolicy.Protocol == protocol && elbPolicy.InternalPort == internalPort && elbPolicy.ExternalPort == externalPort && elbPolicy.ILB == isILB {
if len(vip) > 0 {
if len(elbPolicy.VIPs) == 0 || elbPolicy.VIPs[0] != vip {
continue
}
}
LogJson(plist, "Found existing Hns loadbalancer policy resource", 1)
return &plist, nil
}
}
//TODO: sourceVip is not used. If required, expose this as a param
var sourceVip string
lb, err := hcsshim.AddLoadBalancer(
endpoints,
isILB,
sourceVip,
vip,
protocol,
internalPort,
externalPort,
)
if err == nil {
LogJson(lb, "Hns loadbalancer policy resource", 1)
}
return lb, err
}
func deleteHnsLoadBalancerPolicy(hnsID string) {
if len(hnsID) == 0 {
// Return silently
return
}
// Cleanup HNS policies
hnsloadBalancer, err := hcsshim.GetPolicyListByID(hnsID)
if err != nil {
klog.Errorf("%v", err)
return
}
LogJson(hnsloadBalancer, "Removing Policy", 2)
_, err = hnsloadBalancer.Delete()
if err != nil {
klog.Errorf("%v", err)
}
}
func deleteHnsEndpoint(hnsID string) {
hnsendpoint, err := hcsshim.GetHNSEndpointByID(hnsID)
if err != nil {
klog.Errorf("%v", err)
return
}
_, err = hnsendpoint.Delete()
if err != nil {
klog.Errorf("%v", err)
}
klog.V(3).Infof("Remote endpoint resource deleted id %s", hnsID)
}
func getHnsNetworkInfo(hnsNetworkName string) (*hnsNetworkInfo, error) { func getHnsNetworkInfo(hnsNetworkName string) (*hnsNetworkInfo, error) {
hnsnetwork, err := hcsshim.GetHNSNetworkByName(hnsNetworkName) hnsnetwork, err := hcsshim.GetHNSNetworkByName(hnsNetworkName)
if err != nil { if err != nil {
@ -663,29 +674,12 @@ func getHnsNetworkInfo(hnsNetworkName string) (*hnsNetworkInfo, error) {
} }
return &hnsNetworkInfo{ return &hnsNetworkInfo{
id: hnsnetwork.Id, id: hnsnetwork.Id,
name: hnsnetwork.Name, name: hnsnetwork.Name,
networkType: hnsnetwork.Type,
}, nil }, nil
} }
func getHnsEndpointByIpAddress(ip net.IP, networkName string) (*hcsshim.HNSEndpoint, error) {
hnsnetwork, err := hcsshim.GetHNSNetworkByName(networkName)
if err != nil {
klog.Errorf("%v", err)
return nil, err
}
endpoints, err := hcsshim.HNSListEndpointRequest()
for _, endpoint := range endpoints {
equal := reflect.DeepEqual(endpoint.IPAddress, ip)
if equal && endpoint.VirtualNetwork == hnsnetwork.Id {
return &endpoint, nil
}
}
return nil, fmt.Errorf("Endpoint %v not found on network %s", ip, networkName)
}
// Sync is called to synchronize the proxier state to hns as soon as possible. // Sync is called to synchronize the proxier state to hns as soon as possible.
func (proxier *Proxier) Sync() { func (proxier *Proxier) Sync() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
@ -714,21 +708,21 @@ func (proxier *Proxier) isInitialized() bool {
func (proxier *Proxier) OnServiceAdd(service *v1.Service) { func (proxier *Proxier) OnServiceAdd(service *v1.Service) {
namespacedName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} namespacedName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name}
if proxier.serviceChanges.update(&namespacedName, nil, service) && proxier.isInitialized() { if proxier.serviceChanges.update(&namespacedName, nil, service, proxier.hns) && proxier.isInitialized() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
} }
} }
func (proxier *Proxier) OnServiceUpdate(oldService, service *v1.Service) { func (proxier *Proxier) OnServiceUpdate(oldService, service *v1.Service) {
namespacedName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} namespacedName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name}
if proxier.serviceChanges.update(&namespacedName, oldService, service) && proxier.isInitialized() { if proxier.serviceChanges.update(&namespacedName, oldService, service, proxier.hns) && proxier.isInitialized() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
} }
} }
func (proxier *Proxier) OnServiceDelete(service *v1.Service) { func (proxier *Proxier) OnServiceDelete(service *v1.Service) {
namespacedName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} namespacedName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name}
if proxier.serviceChanges.update(&namespacedName, service, nil) && proxier.isInitialized() { if proxier.serviceChanges.update(&namespacedName, service, nil, proxier.hns) && proxier.isInitialized() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
} }
} }
@ -789,21 +783,21 @@ func (proxier *Proxier) updateServiceMap() (result updateServiceMapResult) {
func (proxier *Proxier) OnEndpointsAdd(endpoints *v1.Endpoints) { func (proxier *Proxier) OnEndpointsAdd(endpoints *v1.Endpoints) {
namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name} namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name}
if proxier.endpointsChanges.update(&namespacedName, nil, endpoints) && proxier.isInitialized() { if proxier.endpointsChanges.update(&namespacedName, nil, endpoints, proxier.hns) && proxier.isInitialized() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
} }
} }
func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *v1.Endpoints) { func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *v1.Endpoints) {
namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name} namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name}
if proxier.endpointsChanges.update(&namespacedName, oldEndpoints, endpoints) && proxier.isInitialized() { if proxier.endpointsChanges.update(&namespacedName, oldEndpoints, endpoints, proxier.hns) && proxier.isInitialized() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
} }
} }
func (proxier *Proxier) OnEndpointsDelete(endpoints *v1.Endpoints) { func (proxier *Proxier) OnEndpointsDelete(endpoints *v1.Endpoints) {
namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name} namespacedName := types.NamespacedName{Namespace: endpoints.Namespace, Name: endpoints.Name}
if proxier.endpointsChanges.update(&namespacedName, endpoints, nil) && proxier.isInitialized() { if proxier.endpointsChanges.update(&namespacedName, endpoints, nil, proxier.hns) && proxier.isInitialized() {
proxier.syncRunner.Run() proxier.syncRunner.Run()
} }
} }
@ -867,7 +861,7 @@ func getLocalIPs(endpointsMap proxyEndpointsMap) map[types.NamespacedName]sets.S
// This function is used for incremental updated of endpointsMap. // This function is used for incremental updated of endpointsMap.
// //
// NOTE: endpoints object should NOT be modified. // NOTE: endpoints object should NOT be modified.
func endpointsToEndpointsMap(endpoints *v1.Endpoints, hostname string) proxyEndpointsMap { func endpointsToEndpointsMap(endpoints *v1.Endpoints, hostname string, hns HostNetworkService) proxyEndpointsMap {
if endpoints == nil { if endpoints == nil {
return nil return nil
} }
@ -880,7 +874,7 @@ func endpointsToEndpointsMap(endpoints *v1.Endpoints, hostname string) proxyEndp
for i := range ss.Ports { for i := range ss.Ports {
port := &ss.Ports[i] port := &ss.Ports[i]
if port.Port == 0 { if port.Port == 0 {
klog.Warningf("ignoring invalid endpoint port %s", port.Name) klog.Warningf("Ignoring invalid endpoint port %s", port.Name)
continue continue
} }
svcPortName := proxy.ServicePortName{ svcPortName := proxy.ServicePortName{
@ -890,11 +884,11 @@ func endpointsToEndpointsMap(endpoints *v1.Endpoints, hostname string) proxyEndp
for i := range ss.Addresses { for i := range ss.Addresses {
addr := &ss.Addresses[i] addr := &ss.Addresses[i]
if addr.IP == "" { if addr.IP == "" {
klog.Warningf("ignoring invalid endpoint port %s with empty host", port.Name) klog.Warningf("Ignoring invalid endpoint port %s with empty host", port.Name)
continue continue
} }
isLocal := addr.NodeName != nil && *addr.NodeName == hostname isLocal := addr.NodeName != nil && *addr.NodeName == hostname
epInfo := newEndpointInfo(addr.IP, uint16(port.Port), isLocal) epInfo := newEndpointInfo(addr.IP, uint16(port.Port), isLocal, hns)
endpointsMap[svcPortName] = append(endpointsMap[svcPortName], epInfo) endpointsMap[svcPortName] = append(endpointsMap[svcPortName], epInfo)
} }
if klog.V(3) { if klog.V(3) {
@ -912,7 +906,7 @@ func endpointsToEndpointsMap(endpoints *v1.Endpoints, hostname string) proxyEndp
// Translates single Service object to proxyServiceMap. // Translates single Service object to proxyServiceMap.
// //
// NOTE: service object should NOT be modified. // NOTE: service object should NOT be modified.
func serviceToServiceMap(service *v1.Service) proxyServiceMap { func serviceToServiceMap(service *v1.Service, hns HostNetworkService) proxyServiceMap {
if service == nil { if service == nil {
return nil return nil
} }
@ -925,7 +919,7 @@ func serviceToServiceMap(service *v1.Service) proxyServiceMap {
for i := range service.Spec.Ports { for i := range service.Spec.Ports {
servicePort := &service.Spec.Ports[i] servicePort := &service.Spec.Ports[i]
svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: servicePort.Name} svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: servicePort.Name}
serviceMap[svcPortName] = newServiceInfo(svcPortName, servicePort, service) serviceMap[svcPortName] = newServiceInfo(svcPortName, servicePort, service, hns)
} }
return serviceMap return serviceMap
} }
@ -972,12 +966,36 @@ func (proxier *Proxier) syncProxyRules() {
continue continue
} }
var hnsEndpoints []hcsshim.HNSEndpoint hnsNetworkName := proxier.network.name
hns := proxier.hns
if proxier.network.networkType == "Overlay" {
serviceVipEndpoint, _ := hns.getEndpointByIpAddress(svcInfo.clusterIP.String(), hnsNetworkName)
if serviceVipEndpoint == nil {
klog.V(4).Infof("No existing remote endpoint for service VIP %v", svcInfo.clusterIP.String())
hnsEndpoint := &endpointsInfo{
ip: svcInfo.clusterIP.String(),
isLocal: false,
macAddress: proxier.hostMac,
providerAddress: proxier.nodeIP.String(),
}
newHnsEndpoint, err := hns.createEndpoint(hnsEndpoint, hnsNetworkName)
if err != nil {
klog.Errorf("Remote endpoint creation failed for service VIP: %v", err)
continue
}
newHnsEndpoint.refCount++
svcInfo.remoteEndpoint = newHnsEndpoint
}
}
var hnsEndpoints []endpointsInfo
klog.V(4).Infof("====Applying Policy for %s====", svcName) klog.V(4).Infof("====Applying Policy for %s====", svcName)
// Create Remote endpoints for every endpoint, corresponding to the service // Create Remote endpoints for every endpoint, corresponding to the service
for _, ep := range proxier.endpointsMap[svcName] { for _, ep := range proxier.endpointsMap[svcName] {
var newHnsEndpoint *hcsshim.HNSEndpoint var newHnsEndpoint *endpointsInfo
hnsNetworkName := proxier.network.name hnsNetworkName := proxier.network.name
var err error var err error
@ -989,14 +1007,14 @@ func (proxier *Proxier) syncProxyRules() {
} }
if len(ep.hnsID) > 0 { if len(ep.hnsID) > 0 {
newHnsEndpoint, err = hcsshim.GetHNSEndpointByID(ep.hnsID) newHnsEndpoint, err = hns.getEndpointByID(ep.hnsID)
} }
if newHnsEndpoint == nil { if newHnsEndpoint == nil {
// First check if an endpoint resource exists for this IP, on the current host // First check if an endpoint resource exists for this IP, on the current host
// A Local endpoint could exist here already // A Local endpoint could exist here already
// A remote endpoint was already created and proxy was restarted // A remote endpoint was already created and proxy was restarted
newHnsEndpoint, err = getHnsEndpointByIpAddress(net.ParseIP(ep.ip), hnsNetworkName) newHnsEndpoint, err = hns.getEndpointByIpAddress(ep.ip, hnsNetworkName)
} }
if newHnsEndpoint == nil { if newHnsEndpoint == nil {
@ -1004,29 +1022,63 @@ func (proxier *Proxier) syncProxyRules() {
klog.Errorf("Local endpoint not found for %v: err: %v on network %s", ep.ip, err, hnsNetworkName) klog.Errorf("Local endpoint not found for %v: err: %v on network %s", ep.ip, err, hnsNetworkName)
continue continue
} }
// hns Endpoint resource was not found, create one
hnsnetwork, err := hcsshim.GetHNSNetworkByName(hnsNetworkName)
if err != nil {
klog.Errorf("%v", err)
continue
}
hnsEndpoint := &hcsshim.HNSEndpoint{ if proxier.network.networkType == "Overlay" {
MacAddress: ep.macAddress, klog.Infof("Updating network %v to check for new remote subnet policies", proxier.network.name)
IPAddress: net.ParseIP(ep.ip), networkName := proxier.network.name
} updatedNetwork, err := hns.getNetworkByName(networkName)
if err != nil {
klog.Fatalf("Failed to get network %v: %v", networkName, err)
}
proxier.network = *updatedNetwork
var providerAddress string
for _, rs := range proxier.network.remoteSubnets {
_, ipNet, err := net.ParseCIDR(rs.destinationPrefix)
if err != nil {
klog.Fatalf("%v", err)
}
if ipNet.Contains(net.ParseIP(ep.ip)) {
providerAddress = rs.providerAddress
}
if ep.ip == rs.providerAddress {
providerAddress = rs.providerAddress
}
}
if len(providerAddress) == 0 {
klog.Errorf("Could not find provider address for %s", ep.ip)
continue
}
hnsEndpoint := &endpointsInfo{
ip: ep.ip,
isLocal: false,
macAddress: conjureMac("02-11", net.ParseIP(ep.ip)),
providerAddress: providerAddress,
}
newHnsEndpoint, err = hnsnetwork.CreateRemoteEndpoint(hnsEndpoint) newHnsEndpoint, err = hns.createEndpoint(hnsEndpoint, hnsNetworkName)
if err != nil { if err != nil {
klog.Errorf("Remote endpoint creation failed: %v", err) klog.Errorf("Remote endpoint creation failed: %v, %s", err, spew.Sdump(hnsEndpoint))
continue continue
}
} else {
hnsEndpoint := &endpointsInfo{
ip: ep.ip,
isLocal: false,
macAddress: ep.macAddress,
}
newHnsEndpoint, err = hns.createEndpoint(hnsEndpoint, hnsNetworkName)
if err != nil {
klog.Errorf("Remote endpoint creation failed: %v", err)
continue
}
} }
} }
// Save the hnsId for reference // Save the hnsId for reference
LogJson(newHnsEndpoint, "Hns Endpoint resource", 1) LogJson(newHnsEndpoint, "Hns Endpoint resource", 1)
hnsEndpoints = append(hnsEndpoints, *newHnsEndpoint) hnsEndpoints = append(hnsEndpoints, *newHnsEndpoint)
ep.hnsID = newHnsEndpoint.Id ep.hnsID = newHnsEndpoint.hnsID
ep.refCount++ ep.refCount++
Log(ep, "Endpoint resource found", 3) Log(ep, "Endpoint resource found", 3)
} }
@ -1044,11 +1096,13 @@ func (proxier *Proxier) syncProxyRules() {
} }
klog.V(4).Infof("Trying to Apply Policies for service %s", spew.Sdump(svcInfo)) klog.V(4).Infof("Trying to Apply Policies for service %s", spew.Sdump(svcInfo))
var hnsLoadBalancer *hcsshim.PolicyList var hnsLoadBalancer *loadBalancerInfo
hnsLoadBalancer, err := getHnsLoadBalancer( hnsLoadBalancer, err := hns.getLoadBalancer(
hnsEndpoints, hnsEndpoints,
false, false,
proxier.isDSR,
proxier.sourceVip,
svcInfo.clusterIP.String(), svcInfo.clusterIP.String(),
Enum(svcInfo.protocol), Enum(svcInfo.protocol),
uint16(svcInfo.targetPort), uint16(svcInfo.targetPort),
@ -1059,15 +1113,17 @@ func (proxier *Proxier) syncProxyRules() {
continue continue
} }
svcInfo.hnsID = hnsLoadBalancer.ID svcInfo.hnsID = hnsLoadBalancer.hnsID
klog.V(3).Infof("Hns LoadBalancer resource created for cluster ip resources %v, Id [%s]", svcInfo.clusterIP, hnsLoadBalancer.ID) klog.V(3).Infof("Hns LoadBalancer resource created for cluster ip resources %v, Id [%s]", svcInfo.clusterIP, hnsLoadBalancer.hnsID)
// If nodePort is specified, user should be able to use nodeIP:nodePort to reach the backend endpoints // If nodePort is specified, user should be able to use nodeIP:nodePort to reach the backend endpoints
if svcInfo.nodePort > 0 { if svcInfo.nodePort > 0 {
hnsLoadBalancer, err := getHnsLoadBalancer( hnsLoadBalancer, err := hns.getLoadBalancer(
hnsEndpoints, hnsEndpoints,
false, false,
"", // VIP has to be empty to automatically select the nodeIP false,
proxier.sourceVip,
"",
Enum(svcInfo.protocol), Enum(svcInfo.protocol),
uint16(svcInfo.targetPort), uint16(svcInfo.targetPort),
uint16(svcInfo.nodePort), uint16(svcInfo.nodePort),
@ -1077,16 +1133,18 @@ func (proxier *Proxier) syncProxyRules() {
continue continue
} }
svcInfo.nodePorthnsID = hnsLoadBalancer.ID svcInfo.nodePorthnsID = hnsLoadBalancer.hnsID
klog.V(3).Infof("Hns LoadBalancer resource created for nodePort resources %v, Id [%s]", svcInfo.clusterIP, hnsLoadBalancer.ID) klog.V(3).Infof("Hns LoadBalancer resource created for nodePort resources %v, Id [%s]", svcInfo.clusterIP, hnsLoadBalancer.hnsID)
} }
// Create a Load Balancer Policy for each external IP // Create a Load Balancer Policy for each external IP
for _, externalIp := range svcInfo.externalIPs { for _, externalIp := range svcInfo.externalIPs {
// Try loading existing policies, if already available // Try loading existing policies, if already available
hnsLoadBalancer, err := getHnsLoadBalancer( hnsLoadBalancer, err = hns.getLoadBalancer(
hnsEndpoints, hnsEndpoints,
false, false,
false,
proxier.sourceVip,
externalIp.ip, externalIp.ip,
Enum(svcInfo.protocol), Enum(svcInfo.protocol),
uint16(svcInfo.targetPort), uint16(svcInfo.targetPort),
@ -1096,15 +1154,17 @@ func (proxier *Proxier) syncProxyRules() {
klog.Errorf("Policy creation failed: %v", err) klog.Errorf("Policy creation failed: %v", err)
continue continue
} }
externalIp.hnsID = hnsLoadBalancer.ID externalIp.hnsID = hnsLoadBalancer.hnsID
klog.V(3).Infof("Hns LoadBalancer resource created for externalIp resources %v, Id[%s]", externalIp, hnsLoadBalancer.ID) klog.V(3).Infof("Hns LoadBalancer resource created for externalIp resources %v, Id[%s]", externalIp, hnsLoadBalancer.hnsID)
} }
// Create a Load Balancer Policy for each loadbalancer ingress // Create a Load Balancer Policy for each loadbalancer ingress
for _, lbIngressIp := range svcInfo.loadBalancerIngressIPs { for _, lbIngressIp := range svcInfo.loadBalancerIngressIPs {
// Try loading existing policies, if already available // Try loading existing policies, if already available
hnsLoadBalancer, err := getHnsLoadBalancer( hnsLoadBalancer, err := hns.getLoadBalancer(
hnsEndpoints, hnsEndpoints,
false, false,
false,
proxier.sourceVip,
lbIngressIp.ip, lbIngressIp.ip,
Enum(svcInfo.protocol), Enum(svcInfo.protocol),
uint16(svcInfo.targetPort), uint16(svcInfo.targetPort),
@ -1114,7 +1174,7 @@ func (proxier *Proxier) syncProxyRules() {
klog.Errorf("Policy creation failed: %v", err) klog.Errorf("Policy creation failed: %v", err)
continue continue
} }
lbIngressIp.hnsID = hnsLoadBalancer.ID lbIngressIp.hnsID = hnsLoadBalancer.hnsID
klog.V(3).Infof("Hns LoadBalancer resource created for loadBalancer Ingress resources %v", lbIngressIp) klog.V(3).Infof("Hns LoadBalancer resource created for loadBalancer Ingress resources %v", lbIngressIp)
} }
svcInfo.policyApplied = true svcInfo.policyApplied = true

View File

@ -0,0 +1,379 @@
// +build windows
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package winkernel
import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/proxy"
"net"
"strings"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const testHostName = "test-hostname"
const macAddress = "00-11-22-33-44-55"
const clusterCIDR = "192.168.1.0/24"
const destinationPrefix = "192.168.2.0/24"
const providerAddress = "10.0.0.3"
const guid = "123ABC"
type fakeHealthChecker struct {
services map[types.NamespacedName]uint16
endpoints map[types.NamespacedName]int
}
func newFakeHealthChecker() *fakeHealthChecker {
return &fakeHealthChecker{
services: map[types.NamespacedName]uint16{},
endpoints: map[types.NamespacedName]int{},
}
}
func (fake *fakeHealthChecker) SyncServices(newServices map[types.NamespacedName]uint16) error {
fake.services = newServices
return nil
}
func (fake *fakeHealthChecker) SyncEndpoints(newEndpoints map[types.NamespacedName]int) error {
fake.endpoints = newEndpoints
return nil
}
type fakeHNS struct{}
func newFakeHNS() *fakeHNS {
return &fakeHNS{}
}
func (hns fakeHNS) getNetworkByName(name string) (*hnsNetworkInfo, error) {
var remoteSubnets []*remoteSubnetInfo
rs := &remoteSubnetInfo{
destinationPrefix: destinationPrefix,
isolationId: 4096,
providerAddress: providerAddress,
drMacAddress: macAddress,
}
remoteSubnets = append(remoteSubnets, rs)
return &hnsNetworkInfo{
id: strings.ToUpper(guid),
name: name,
networkType: "Overlay",
remoteSubnets: remoteSubnets,
}, nil
}
func (hns fakeHNS) getEndpointByID(id string) (*endpointsInfo, error) {
return nil, nil
}
func (hns fakeHNS) getEndpointByIpAddress(ip string, networkName string) (*endpointsInfo, error) {
_, ipNet, _ := net.ParseCIDR(destinationPrefix)
if ipNet.Contains(net.ParseIP(ip)) {
return &endpointsInfo{
ip: ip,
isLocal: true,
macAddress: macAddress,
hnsID: guid,
hns: hns,
}, nil
}
return nil, nil
}
func (hns fakeHNS) createEndpoint(ep *endpointsInfo, networkName string) (*endpointsInfo, error) {
return &endpointsInfo{
ip: ep.ip,
isLocal: ep.isLocal,
macAddress: ep.macAddress,
hnsID: guid,
hns: hns,
}, nil
}
func (hns fakeHNS) deleteEndpoint(hnsID string) error {
return nil
}
func (hns fakeHNS) getLoadBalancer(endpoints []endpointsInfo, isILB bool, isDSR bool, sourceVip string, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*loadBalancerInfo, error) {
return &loadBalancerInfo{
hnsID: guid,
}, nil
}
func (hns fakeHNS) deleteLoadBalancer(hnsID string) error {
return nil
}
func NewFakeProxier(syncPeriod time.Duration, minSyncPeriod time.Duration, clusterCIDR string, hostname string, nodeIP net.IP, networkType string) *Proxier {
sourceVip := "192.168.1.2"
hnsNetworkInfo := &hnsNetworkInfo{
name: "TestNetwork",
networkType: networkType,
}
proxier := &Proxier{
portsMap: make(map[localPort]closeable),
serviceMap: make(proxyServiceMap),
serviceChanges: newServiceChangeMap(),
endpointsMap: make(proxyEndpointsMap),
endpointsChanges: newEndpointsChangeMap(hostname),
clusterCIDR: clusterCIDR,
hostname: testHostName,
nodeIP: nodeIP,
healthChecker: newFakeHealthChecker(),
network: *hnsNetworkInfo,
sourceVip: sourceVip,
hostMac: macAddress,
isDSR: false,
hns: newFakeHNS(),
}
return proxier
}
func TestCreateServiceVip(t *testing.T) {
syncPeriod := 30 * time.Second
proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", net.ParseIP("10.0.0.1"), "Overlay")
if proxier == nil {
t.Error()
}
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcExternalIPs := "50.60.70.81"
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
timeoutSeconds := v1.DefaultClientIPServiceAffinitySeconds
makeServiceMap(proxier,
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
svc.Spec.ExternalIPs = []string{svcExternalIPs}
svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
svc.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{
ClientIP: &v1.ClientIPConfig{
TimeoutSeconds: &timeoutSeconds,
},
}
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
makeEndpointsMap(proxier)
proxier.syncProxyRules()
if proxier.serviceMap[svcPortName].remoteEndpoint == nil {
t.Error()
}
if proxier.serviceMap[svcPortName].remoteEndpoint.ip != svcIP {
t.Error()
}
}
func TestCreateRemoteEndpointOverlay(t *testing.T) {
syncPeriod := 30 * time.Second
proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", net.ParseIP("10.0.0.1"), "Overlay")
if proxier == nil {
t.Error()
}
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(proxier,
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
makeEndpointsMap(proxier,
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIpAddressRemote,
}},
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
proxier.syncProxyRules()
if proxier.endpointsMap[svcPortName][0].hnsID != guid {
t.Errorf("%v does not match %v", proxier.endpointsMap[svcPortName][0].hnsID, guid)
}
}
func TestCreateRemoteEndpointL2Bridge(t *testing.T) {
syncPeriod := 30 * time.Second
proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", net.ParseIP("10.0.0.1"), "L2Bridge")
if proxier == nil {
t.Error()
}
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(proxier,
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
makeEndpointsMap(proxier,
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIpAddressRemote,
}},
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
proxier.syncProxyRules()
if proxier.endpointsMap[svcPortName][0].hnsID != guid {
t.Errorf("%v does not match %v", proxier.endpointsMap[svcPortName][0].hnsID, guid)
}
}
func TestCreateLoadBalancer(t *testing.T) {
syncPeriod := 30 * time.Second
proxier := NewFakeProxier(syncPeriod, syncPeriod, clusterCIDR, "testhost", net.ParseIP("10.0.0.1"), "Overlay")
if proxier == nil {
t.Error()
}
svcIP := "10.20.30.41"
svcPort := 80
svcNodePort := 3001
svcPortName := proxy.ServicePortName{
NamespacedName: makeNSN("ns1", "svc1"),
Port: "p80",
}
makeServiceMap(proxier,
makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
svc.Spec.Type = "NodePort"
svc.Spec.ClusterIP = svcIP
svc.Spec.Ports = []v1.ServicePort{{
Name: svcPortName.Port,
Port: int32(svcPort),
Protocol: v1.ProtocolTCP,
NodePort: int32(svcNodePort),
}}
}),
)
makeEndpointsMap(proxier,
makeTestEndpoints(svcPortName.Namespace, svcPortName.Name, func(ept *v1.Endpoints) {
ept.Subsets = []v1.EndpointSubset{{
Addresses: []v1.EndpointAddress{{
IP: epIpAddressRemote,
}},
Ports: []v1.EndpointPort{{
Name: svcPortName.Port,
Port: int32(svcPort),
}},
}}
}),
)
proxier.syncProxyRules()
if proxier.serviceMap[svcPortName].hnsID != guid {
t.Errorf("%v does not match %v", proxier.serviceMap[svcPortName].hnsID, guid)
}
}
func makeNSN(namespace, name string) types.NamespacedName {
return types.NamespacedName{Namespace: namespace, Name: name}
}
func makeServiceMap(proxier *Proxier, allServices ...*v1.Service) {
for i := range allServices {
proxier.OnServiceAdd(allServices[i])
}
proxier.mu.Lock()
defer proxier.mu.Unlock()
proxier.servicesSynced = true
}
func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Annotations: map[string]string{},
},
Spec: v1.ServiceSpec{},
Status: v1.ServiceStatus{},
}
svcFunc(svc)
return svc
}
func makeEndpointsMap(proxier *Proxier, allEndpoints ...*v1.Endpoints) {
for i := range allEndpoints {
proxier.OnEndpointsAdd(allEndpoints[i])
}
proxier.mu.Lock()
defer proxier.mu.Unlock()
proxier.endpointsSynced = true
}
func makeTestEndpoints(namespace, name string, eptFunc func(*v1.Endpoints)) *v1.Endpoints {
ept := &v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
}
eptFunc(ept)
return ept
}