Merge pull request #69495 from wgliang/feature/movenodoinfofunctions

[scheduler cleanup phase 1]: Move NodeInfo utils into pkg/scheduler/cache
pull/58/head
k8s-ci-robot 2018-10-11 07:12:40 -07:00 committed by GitHub
commit 539bdbc355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 393 additions and 356 deletions

View File

@ -19,7 +19,7 @@ package predicates
import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
schedutil "k8s.io/kubernetes/pkg/scheduler/util"
schedulercache "k8s.io/kubernetes/pkg/scheduler/cache"
)
// FindLabelsInSet gets as many key/value pairs as possible out of a label set.
@ -68,7 +68,7 @@ func CreateSelectorFromLabels(aL map[string]string) labels.Selector {
// portsConflict check whether existingPorts and wantPorts conflict with each other
// return true if we have a conflict
func portsConflict(existingPorts schedutil.HostPortInfo, wantPorts []*v1.ContainerPort) bool {
func portsConflict(existingPorts schedulercache.HostPortInfo, wantPorts []*v1.ContainerPort) bool {
for _, cp := range wantPorts {
if existingPorts.CheckConflict(cp.HostIP, string(cp.Protocol), cp.HostPort) {
return true

View File

@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"host_ports.go",
"node_info.go",
"util.go",
],
@ -11,7 +12,6 @@ go_library(
deps = [
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/scheduler/algorithm/priorities/util:go_default_library",
"//pkg/scheduler/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
@ -22,12 +22,12 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"host_ports_test.go",
"node_info_test.go",
"util_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/scheduler/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",

135
pkg/scheduler/cache/host_ports.go vendored Normal file
View File

@ -0,0 +1,135 @@
/*
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 cache
import (
"k8s.io/api/core/v1"
)
// DefaultBindAllHostIP defines the default ip address used to bind to all host.
const DefaultBindAllHostIP = "0.0.0.0"
// ProtocolPort represents a protocol port pair, e.g. tcp:80.
type ProtocolPort struct {
Protocol string
Port int32
}
// NewProtocolPort creates a ProtocolPort instance.
func NewProtocolPort(protocol string, port int32) *ProtocolPort {
pp := &ProtocolPort{
Protocol: protocol,
Port: port,
}
if len(pp.Protocol) == 0 {
pp.Protocol = string(v1.ProtocolTCP)
}
return pp
}
// HostPortInfo stores mapping from ip to a set of ProtocolPort
type HostPortInfo map[string]map[ProtocolPort]struct{}
// Add adds (ip, protocol, port) to HostPortInfo
func (h HostPortInfo) Add(ip, protocol string, port int32) {
if port <= 0 {
return
}
h.sanitize(&ip, &protocol)
pp := NewProtocolPort(protocol, port)
if _, ok := h[ip]; !ok {
h[ip] = map[ProtocolPort]struct{}{
*pp: {},
}
return
}
h[ip][*pp] = struct{}{}
}
// Remove removes (ip, protocol, port) from HostPortInfo
func (h HostPortInfo) Remove(ip, protocol string, port int32) {
if port <= 0 {
return
}
h.sanitize(&ip, &protocol)
pp := NewProtocolPort(protocol, port)
if m, ok := h[ip]; ok {
delete(m, *pp)
if len(h[ip]) == 0 {
delete(h, ip)
}
}
}
// Len returns the total number of (ip, protocol, port) tuple in HostPortInfo
func (h HostPortInfo) Len() int {
length := 0
for _, m := range h {
length += len(m)
}
return length
}
// CheckConflict checks if the input (ip, protocol, port) conflicts with the existing
// ones in HostPortInfo.
func (h HostPortInfo) CheckConflict(ip, protocol string, port int32) bool {
if port <= 0 {
return false
}
h.sanitize(&ip, &protocol)
pp := NewProtocolPort(protocol, port)
// If ip is 0.0.0.0 check all IP's (protocol, port) pair
if ip == DefaultBindAllHostIP {
for _, m := range h {
if _, ok := m[*pp]; ok {
return true
}
}
return false
}
// If ip isn't 0.0.0.0, only check IP and 0.0.0.0's (protocol, port) pair
for _, key := range []string{DefaultBindAllHostIP, ip} {
if m, ok := h[key]; ok {
if _, ok2 := m[*pp]; ok2 {
return true
}
}
}
return false
}
// sanitize the parameters
func (h HostPortInfo) sanitize(ip, protocol *string) {
if len(*ip) == 0 {
*ip = DefaultBindAllHostIP
}
if len(*protocol) == 0 {
*protocol = string(v1.ProtocolTCP)
}
}

231
pkg/scheduler/cache/host_ports_test.go vendored Normal file
View File

@ -0,0 +1,231 @@
/*
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 cache
import (
"testing"
)
type hostPortInfoParam struct {
protocol, ip string
port int32
}
func TestHostPortInfo_AddRemove(t *testing.T) {
tests := []struct {
desc string
added []hostPortInfoParam
removed []hostPortInfoParam
length int
}{
{
desc: "normal add case",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
// this might not make sense in real case, but the struct doesn't forbid it.
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
{"TCP", "0.0.0.0", 0},
{"TCP", "0.0.0.0", -1},
},
length: 8,
},
{
desc: "empty ip and protocol add should work",
added: []hostPortInfoParam{
{"", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"", "127.0.0.1", 81},
{"", "127.0.0.1", 82},
{"", "", 79},
{"UDP", "", 80},
{"", "", 81},
{"", "", 82},
{"", "", 0},
{"", "", -1},
},
length: 8,
},
{
desc: "normal remove case",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
removed: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
length: 0,
},
{
desc: "empty ip and protocol remove should work",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
removed: []hostPortInfoParam{
{"", "127.0.0.1", 79},
{"", "127.0.0.1", 81},
{"", "127.0.0.1", 82},
{"UDP", "127.0.0.1", 80},
{"", "", 79},
{"", "", 81},
{"", "", 82},
{"UDP", "", 80},
},
length: 0,
},
}
for _, test := range tests {
hp := make(HostPortInfo)
for _, param := range test.added {
hp.Add(param.ip, param.protocol, param.port)
}
for _, param := range test.removed {
hp.Remove(param.ip, param.protocol, param.port)
}
if hp.Len() != test.length {
t.Errorf("%v failed: expect length %d; got %d", test.desc, test.length, hp.Len())
t.Error(hp)
}
}
}
func TestHostPortInfo_Check(t *testing.T) {
tests := []struct {
desc string
added []hostPortInfoParam
check hostPortInfoParam
expect bool
}{
{
desc: "empty check should check 0.0.0.0 and TCP",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"", "", 81},
expect: false,
},
{
desc: "empty check should check 0.0.0.0 and TCP (conflicted)",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"", "", 80},
expect: true,
},
{
desc: "empty port check should pass",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"", "", 0},
expect: false,
},
{
desc: "0.0.0.0 should check all registered IPs",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"TCP", "0.0.0.0", 80},
expect: true,
},
{
desc: "0.0.0.0 with different protocol should be allowed",
added: []hostPortInfoParam{
{"UDP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"TCP", "0.0.0.0", 80},
expect: false,
},
{
desc: "0.0.0.0 with different port should be allowed",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
},
check: hostPortInfoParam{"TCP", "0.0.0.0", 80},
expect: false,
},
{
desc: "normal ip should check all registered 0.0.0.0",
added: []hostPortInfoParam{
{"TCP", "0.0.0.0", 80},
},
check: hostPortInfoParam{"TCP", "127.0.0.1", 80},
expect: true,
},
{
desc: "normal ip with different port/protocol should be allowed (0.0.0.0)",
added: []hostPortInfoParam{
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
check: hostPortInfoParam{"TCP", "127.0.0.1", 80},
expect: false,
},
{
desc: "normal ip with different port/protocol should be allowed",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
},
check: hostPortInfoParam{"TCP", "127.0.0.1", 80},
expect: false,
},
}
for _, test := range tests {
hp := make(HostPortInfo)
for _, param := range test.added {
hp.Add(param.ip, param.protocol, param.port)
}
if hp.CheckConflict(test.check.ip, test.check.protocol, test.check.port) != test.expect {
t.Errorf("%v failed, expected %t; got %t", test.desc, test.expect, !test.expect)
}
}
}

View File

@ -28,7 +28,6 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
priorityutil "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util"
"k8s.io/kubernetes/pkg/scheduler/util"
)
var (
@ -51,7 +50,7 @@ type NodeInfo struct {
pods []*v1.Pod
podsWithAffinity []*v1.Pod
usedPorts util.HostPortInfo
usedPorts HostPortInfo
// Total requested resource of all pods on this node.
// It includes assumed pods which scheduler sends binding to apiserver but
@ -269,7 +268,7 @@ func NewNodeInfo(pods ...*v1.Pod) *NodeInfo {
allocatableResource: &Resource{},
TransientInfo: NewTransientSchedulerInfo(),
generation: nextGeneration(),
usedPorts: make(util.HostPortInfo),
usedPorts: make(HostPortInfo),
imageStates: make(map[string]*ImageStateSummary),
}
for _, pod := range pods {
@ -300,7 +299,7 @@ func (n *NodeInfo) SetPods(pods []*v1.Pod) {
}
// UsedPorts returns used ports on this node.
func (n *NodeInfo) UsedPorts() util.HostPortInfo {
func (n *NodeInfo) UsedPorts() HostPortInfo {
if n == nil {
return nil
}
@ -308,7 +307,7 @@ func (n *NodeInfo) UsedPorts() util.HostPortInfo {
}
// SetUsedPorts sets the used ports on this node.
func (n *NodeInfo) SetUsedPorts(newUsedPorts util.HostPortInfo) {
func (n *NodeInfo) SetUsedPorts(newUsedPorts HostPortInfo) {
n.usedPorts = newUsedPorts
}
@ -443,7 +442,7 @@ func (n *NodeInfo) Clone() *NodeInfo {
memoryPressureCondition: n.memoryPressureCondition,
diskPressureCondition: n.diskPressureCondition,
pidPressureCondition: n.pidPressureCondition,
usedPorts: make(util.HostPortInfo),
usedPorts: make(HostPortInfo),
imageStates: n.imageStates,
generation: n.generation,
}
@ -451,10 +450,10 @@ func (n *NodeInfo) Clone() *NodeInfo {
clone.pods = append([]*v1.Pod(nil), n.pods...)
}
if len(n.usedPorts) > 0 {
// util.HostPortInfo is a map-in-map struct
// HostPortInfo is a map-in-map struct
// make sure it's deep copied
for ip, portMap := range n.usedPorts {
clone.usedPorts[ip] = make(map[util.ProtocolPort]struct{})
clone.usedPorts[ip] = make(map[ProtocolPort]struct{})
for protocolPort, v := range portMap {
clone.usedPorts[ip][protocolPort] = v
}

View File

@ -26,7 +26,6 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/scheduler/util"
)
func TestNewResource(t *testing.T) {
@ -303,8 +302,8 @@ func TestNewNodeInfo(t *testing.T) {
TransientInfo: NewTransientSchedulerInfo(),
allocatableResource: &Resource{},
generation: 2,
usedPorts: util.HostPortInfo{
"127.0.0.1": map[util.ProtocolPort]struct{}{
usedPorts: HostPortInfo{
"127.0.0.1": map[ProtocolPort]struct{}{
{Protocol: "TCP", Port: 80}: {},
{Protocol: "TCP", Port: 8080}: {},
},
@ -392,8 +391,8 @@ func TestNodeInfoClone(t *testing.T) {
TransientInfo: NewTransientSchedulerInfo(),
allocatableResource: &Resource{},
generation: 2,
usedPorts: util.HostPortInfo{
"127.0.0.1": map[util.ProtocolPort]struct{}{
usedPorts: HostPortInfo{
"127.0.0.1": map[ProtocolPort]struct{}{
{Protocol: "TCP", Port: 80}: {},
{Protocol: "TCP", Port: 8080}: {},
},
@ -462,8 +461,8 @@ func TestNodeInfoClone(t *testing.T) {
TransientInfo: NewTransientSchedulerInfo(),
allocatableResource: &Resource{},
generation: 2,
usedPorts: util.HostPortInfo{
"127.0.0.1": map[util.ProtocolPort]struct{}{
usedPorts: HostPortInfo{
"127.0.0.1": map[ProtocolPort]struct{}{
{Protocol: "TCP", Port: 80}: {},
{Protocol: "TCP", Port: 8080}: {},
},
@ -621,8 +620,8 @@ func TestNodeInfoAddPod(t *testing.T) {
TransientInfo: NewTransientSchedulerInfo(),
allocatableResource: &Resource{},
generation: 2,
usedPorts: util.HostPortInfo{
"127.0.0.1": map[util.ProtocolPort]struct{}{
usedPorts: HostPortInfo{
"127.0.0.1": map[ProtocolPort]struct{}{
{Protocol: "TCP", Port: 80}: {},
{Protocol: "TCP", Port: 8080}: {},
},
@ -740,8 +739,8 @@ func TestNodeInfoRemovePod(t *testing.T) {
TransientInfo: NewTransientSchedulerInfo(),
allocatableResource: &Resource{},
generation: 2,
usedPorts: util.HostPortInfo{
"127.0.0.1": map[util.ProtocolPort]struct{}{
usedPorts: HostPortInfo{
"127.0.0.1": map[ProtocolPort]struct{}{
{Protocol: "TCP", Port: 80}: {},
{Protocol: "TCP", Port: 8080}: {},
},
@ -857,8 +856,8 @@ func TestNodeInfoRemovePod(t *testing.T) {
TransientInfo: NewTransientSchedulerInfo(),
allocatableResource: &Resource{},
generation: 3,
usedPorts: util.HostPortInfo{
"127.0.0.1": map[util.ProtocolPort]struct{}{
usedPorts: HostPortInfo{
"127.0.0.1": map[ProtocolPort]struct{}{
{Protocol: "TCP", Port: 8080}: {},
},
},

View File

@ -34,7 +34,6 @@ go_test(
"//pkg/kubelet/apis:go_default_library",
"//pkg/scheduler/algorithm/priorities/util:go_default_library",
"//pkg/scheduler/cache:go_default_library",
"//pkg/scheduler/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",

View File

@ -32,8 +32,6 @@ import (
"k8s.io/kubernetes/pkg/features"
priorityutil "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/util"
schedulercache "k8s.io/kubernetes/pkg/scheduler/cache"
"k8s.io/kubernetes/pkg/scheduler/util"
schedutil "k8s.io/kubernetes/pkg/scheduler/util"
)
func deepEqualWithoutGeneration(t *testing.T, testcase int, actual, expected *schedulercache.NodeInfo) {
@ -67,8 +65,8 @@ func (b *hostPortInfoBuilder) add(protocol, ip string, port int32) *hostPortInfo
return b
}
func (b *hostPortInfoBuilder) build() schedutil.HostPortInfo {
res := make(schedutil.HostPortInfo)
func (b *hostPortInfoBuilder) build() schedulercache.HostPortInfo {
res := make(schedulercache.HostPortInfo)
for _, param := range b.inputs {
res.Add(param.ip, param.protocol, param.port)
}
@ -78,7 +76,7 @@ func (b *hostPortInfoBuilder) build() schedutil.HostPortInfo {
func newNodeInfo(requestedResource *schedulercache.Resource,
nonzeroRequest *schedulercache.Resource,
pods []*v1.Pod,
usedPorts util.HostPortInfo,
usedPorts schedulercache.HostPortInfo,
imageStates map[string]*schedulercache.ImageStateSummary,
) *schedulercache.NodeInfo {
nodeInfo := schedulercache.NewNodeInfo(pods...)
@ -747,7 +745,7 @@ func TestEphemeralStorageResource(t *testing.T) {
Memory: priorityutil.DefaultMemoryRequest,
},
[]*v1.Pod{podE},
schedutil.HostPortInfo{},
schedulercache.HostPortInfo{},
make(map[string]*schedulercache.ImageStateSummary),
),
},

View File

@ -25,120 +25,6 @@ import (
"k8s.io/kubernetes/pkg/features"
)
// DefaultBindAllHostIP defines the default ip address used to bind to all host.
const DefaultBindAllHostIP = "0.0.0.0"
// ProtocolPort represents a protocol port pair, e.g. tcp:80.
type ProtocolPort struct {
Protocol string
Port int32
}
// NewProtocolPort creates a ProtocolPort instance.
func NewProtocolPort(protocol string, port int32) *ProtocolPort {
pp := &ProtocolPort{
Protocol: protocol,
Port: port,
}
if len(pp.Protocol) == 0 {
pp.Protocol = string(v1.ProtocolTCP)
}
return pp
}
// HostPortInfo stores mapping from ip to a set of ProtocolPort
type HostPortInfo map[string]map[ProtocolPort]struct{}
// Add adds (ip, protocol, port) to HostPortInfo
func (h HostPortInfo) Add(ip, protocol string, port int32) {
if port <= 0 {
return
}
h.sanitize(&ip, &protocol)
pp := NewProtocolPort(protocol, port)
if _, ok := h[ip]; !ok {
h[ip] = map[ProtocolPort]struct{}{
*pp: {},
}
return
}
h[ip][*pp] = struct{}{}
}
// Remove removes (ip, protocol, port) from HostPortInfo
func (h HostPortInfo) Remove(ip, protocol string, port int32) {
if port <= 0 {
return
}
h.sanitize(&ip, &protocol)
pp := NewProtocolPort(protocol, port)
if m, ok := h[ip]; ok {
delete(m, *pp)
if len(h[ip]) == 0 {
delete(h, ip)
}
}
}
// Len returns the total number of (ip, protocol, port) tuple in HostPortInfo
func (h HostPortInfo) Len() int {
length := 0
for _, m := range h {
length += len(m)
}
return length
}
// CheckConflict checks if the input (ip, protocol, port) conflicts with the existing
// ones in HostPortInfo.
func (h HostPortInfo) CheckConflict(ip, protocol string, port int32) bool {
if port <= 0 {
return false
}
h.sanitize(&ip, &protocol)
pp := NewProtocolPort(protocol, port)
// If ip is 0.0.0.0 check all IP's (protocol, port) pair
if ip == DefaultBindAllHostIP {
for _, m := range h {
if _, ok := m[*pp]; ok {
return true
}
}
return false
}
// If ip isn't 0.0.0.0, only check IP and 0.0.0.0's (protocol, port) pair
for _, key := range []string{DefaultBindAllHostIP, ip} {
if m, ok := h[key]; ok {
if _, ok2 := m[*pp]; ok2 {
return true
}
}
}
return false
}
// sanitize the parameters
func (h HostPortInfo) sanitize(ip, protocol *string) {
if len(*ip) == 0 {
*ip = DefaultBindAllHostIP
}
if len(*protocol) == 0 {
*protocol = string(v1.ProtocolTCP)
}
}
// GetContainerPorts returns the used host ports of Pods: if 'port' was used, a 'port:true' pair
// will be in the result; but it does not resolve port conflict.
func GetContainerPorts(pods ...*v1.Pod) []*v1.ContainerPort {

View File

@ -96,216 +96,6 @@ func TestSortableList(t *testing.T) {
}
}
type hostPortInfoParam struct {
protocol, ip string
port int32
}
func TestHostPortInfo_AddRemove(t *testing.T) {
tests := []struct {
desc string
added []hostPortInfoParam
removed []hostPortInfoParam
length int
}{
{
desc: "normal add case",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
// this might not make sense in real case, but the struct doesn't forbid it.
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
{"TCP", "0.0.0.0", 0},
{"TCP", "0.0.0.0", -1},
},
length: 8,
},
{
desc: "empty ip and protocol add should work",
added: []hostPortInfoParam{
{"", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"", "127.0.0.1", 81},
{"", "127.0.0.1", 82},
{"", "", 79},
{"UDP", "", 80},
{"", "", 81},
{"", "", 82},
{"", "", 0},
{"", "", -1},
},
length: 8,
},
{
desc: "normal remove case",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
removed: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
length: 0,
},
{
desc: "empty ip and protocol remove should work",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
removed: []hostPortInfoParam{
{"", "127.0.0.1", 79},
{"", "127.0.0.1", 81},
{"", "127.0.0.1", 82},
{"UDP", "127.0.0.1", 80},
{"", "", 79},
{"", "", 81},
{"", "", 82},
{"UDP", "", 80},
},
length: 0,
},
}
for _, test := range tests {
hp := make(HostPortInfo)
for _, param := range test.added {
hp.Add(param.ip, param.protocol, param.port)
}
for _, param := range test.removed {
hp.Remove(param.ip, param.protocol, param.port)
}
if hp.Len() != test.length {
t.Errorf("%v failed: expect length %d; got %d", test.desc, test.length, hp.Len())
t.Error(hp)
}
}
}
func TestHostPortInfo_Check(t *testing.T) {
tests := []struct {
desc string
added []hostPortInfoParam
check hostPortInfoParam
expect bool
}{
{
desc: "empty check should check 0.0.0.0 and TCP",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"", "", 81},
expect: false,
},
{
desc: "empty check should check 0.0.0.0 and TCP (conflicted)",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"", "", 80},
expect: true,
},
{
desc: "empty port check should pass",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"", "", 0},
expect: false,
},
{
desc: "0.0.0.0 should check all registered IPs",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"TCP", "0.0.0.0", 80},
expect: true,
},
{
desc: "0.0.0.0 with different protocol should be allowed",
added: []hostPortInfoParam{
{"UDP", "127.0.0.1", 80},
},
check: hostPortInfoParam{"TCP", "0.0.0.0", 80},
expect: false,
},
{
desc: "0.0.0.0 with different port should be allowed",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
},
check: hostPortInfoParam{"TCP", "0.0.0.0", 80},
expect: false,
},
{
desc: "normal ip should check all registered 0.0.0.0",
added: []hostPortInfoParam{
{"TCP", "0.0.0.0", 80},
},
check: hostPortInfoParam{"TCP", "127.0.0.1", 80},
expect: true,
},
{
desc: "normal ip with different port/protocol should be allowed (0.0.0.0)",
added: []hostPortInfoParam{
{"TCP", "0.0.0.0", 79},
{"UDP", "0.0.0.0", 80},
{"TCP", "0.0.0.0", 81},
{"TCP", "0.0.0.0", 82},
},
check: hostPortInfoParam{"TCP", "127.0.0.1", 80},
expect: false,
},
{
desc: "normal ip with different port/protocol should be allowed",
added: []hostPortInfoParam{
{"TCP", "127.0.0.1", 79},
{"UDP", "127.0.0.1", 80},
{"TCP", "127.0.0.1", 81},
{"TCP", "127.0.0.1", 82},
},
check: hostPortInfoParam{"TCP", "127.0.0.1", 80},
expect: false,
},
}
for _, test := range tests {
hp := make(HostPortInfo)
for _, param := range test.added {
hp.Add(param.ip, param.protocol, param.port)
}
if hp.CheckConflict(test.check.ip, test.check.protocol, test.check.port) != test.expect {
t.Errorf("%v failed, expected %t; got %t", test.desc, test.expect, !test.expect)
}
}
}
func TestGetContainerPorts(t *testing.T) {
tests := []struct {
pod1 *v1.Pod