Allow same-hostport-different-protocol

This commit is contained in:
Tim Hockin 2015-05-18 22:18:40 -07:00
parent dc81fe1f12
commit c7bf373d98
3 changed files with 22 additions and 19 deletions

View File

@ -673,22 +673,23 @@ func validateProbe(probe *api.Probe) errs.ValidationErrorList {
return allErrs return allErrs
} }
// AccumulateUniquePorts runs an extraction function on each Port of each Container, // accumulateUniquePorts runs an extraction function on each Port of each Container,
// accumulating the results and returning an error if any ports conflict. // accumulating the results and returning an error if any ports conflict.
func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool, extract func(*api.ContainerPort) int) errs.ValidationErrorList { func accumulateUniqueHostPorts(containers []api.Container, accumulator map[string]bool) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{} allErrs := errs.ValidationErrorList{}
for ci, ctr := range containers { for ci, ctr := range containers {
cErrs := errs.ValidationErrorList{} cErrs := errs.ValidationErrorList{}
for pi := range ctr.Ports { for pi := range ctr.Ports {
port := extract(&ctr.Ports[pi]) port := ctr.Ports[pi].HostPort
if port == 0 { if port == 0 {
continue continue
} }
if accumulator[port] { str := fmt.Sprintf("%d/%s", port, ctr.Ports[pi].Protocol)
cErrs = append(cErrs, errs.NewFieldDuplicate("port", port)) if accumulator[str] {
cErrs = append(cErrs, errs.NewFieldDuplicate("port", str))
} else { } else {
accumulator[port] = true accumulator[str] = true
} }
} }
allErrs = append(allErrs, cErrs.PrefixIndex(ci)...) allErrs = append(allErrs, cErrs.PrefixIndex(ci)...)
@ -696,11 +697,11 @@ func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool,
return allErrs return allErrs
} }
// checkHostPortConflicts checks for colliding Port.HostPort values across // ValidateHostPorts checks for colliding Port.HostPort values across
// a slice of containers. // a slice of containers.
func checkHostPortConflicts(containers []api.Container) errs.ValidationErrorList { func ValidateHostPorts(containers []api.Container) errs.ValidationErrorList {
allPorts := map[int]bool{} allPorts := map[string]bool{}
return AccumulateUniquePorts(containers, allPorts, func(p *api.ContainerPort) int { return p.HostPort }) return accumulateUniqueHostPorts(containers, allPorts)
} }
func validateExecAction(exec *api.ExecAction) errs.ValidationErrorList { func validateExecAction(exec *api.ExecAction) errs.ValidationErrorList {
@ -817,11 +818,7 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs
allErrs = append(allErrs, cErrs.PrefixIndex(i)...) allErrs = append(allErrs, cErrs.PrefixIndex(i)...)
} }
// Check for colliding ports across all containers. // Check for colliding ports across all containers.
// TODO(thockin): This really is dependent on the network config of the host (IP per pod?) allErrs = append(allErrs, ValidateHostPorts(containers)...)
// and the config of the new manifest. But we have not specced that out yet, so we'll just
// make some assumptions for now. As of now, pods share a network namespace, which means that
// every Port.HostPort across the whole pod must be unique.
allErrs = append(allErrs, checkHostPortConflicts(containers)...)
return allErrs return allErrs
} }

View File

@ -785,6 +785,15 @@ func TestValidateContainers(t *testing.T) {
}, },
ImagePullPolicy: "IfNotPresent", ImagePullPolicy: "IfNotPresent",
}, },
{
Name: "same-host-port-different-protocol",
Image: "image",
Ports: []api.ContainerPort{
{ContainerPort: 80, HostPort: 80, Protocol: "TCP"},
{ContainerPort: 80, HostPort: 80, Protocol: "UDP"},
},
ImagePullPolicy: "IfNotPresent",
},
{Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)}, {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)},
} }
if errs := validateContainers(successCase, volumes); len(errs) != 0 { if errs := validateContainers(successCase, volumes); len(errs) != 0 {

View File

@ -1354,14 +1354,11 @@ func (s podsByCreationTime) Less(i, j int) bool {
// checkHostPortConflicts detects pods with conflicted host ports. // checkHostPortConflicts detects pods with conflicted host ports.
func checkHostPortConflicts(pods []*api.Pod) (fitting []*api.Pod, notFitting []*api.Pod) { func checkHostPortConflicts(pods []*api.Pod) (fitting []*api.Pod, notFitting []*api.Pod) {
ports := map[int]bool{}
extract := func(p *api.ContainerPort) int { return p.HostPort }
// Respect the pod creation order when resolving conflicts. // Respect the pod creation order when resolving conflicts.
sort.Sort(podsByCreationTime(pods)) sort.Sort(podsByCreationTime(pods))
for _, pod := range pods { for _, pod := range pods {
if errs := validation.AccumulateUniquePorts(pod.Spec.Containers, ports, extract); len(errs) != 0 { if errs := validation.ValidateHostPorts(pod.Spec.Containers); len(errs) != 0 {
glog.Errorf("Pod %q: HostPort is already allocated, ignoring: %v", kubecontainer.GetPodFullName(pod), errs) glog.Errorf("Pod %q: HostPort is already allocated, ignoring: %v", kubecontainer.GetPodFullName(pod), errs)
notFitting = append(notFitting, pod) notFitting = append(notFitting, pod)
continue continue