Change:
Pods which use to bind both TCP and UDP sockets to the same port number are rejected with the error: An example pod follows.
Looks like we don't check protocol
The issue was discussed before in , which was closed due to it being low priority.
Hmm, that's 2 pods and the scheduler, this is 2 containers in the same pod and validation at create time. Maybe we should just be more clear about where we stand with hostPort.
Posting here what I posted in the other bug: This can't be worked around when running NFS from a pod. Linux does not allow the NFS port (2049) to be changed, and the Portmap port (111) also cannot be changed. Additionally, you can't separate the UDP from the TCP ports.
Why does NFS need host ports? , Russell Harmon wrote:
Fix is in , Tim Hockin wrote:

Discussion:
return allErrs } <del> // AccumulateUniquePorts runs an extraction function on each Port of each Container, </del> <ins> // AccumulateUniqueHostPorts extracts each HostPort of each Container, </ins> // accumulating the results and returning an error if any ports conflict. <del> func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool, extract func(*api.ContainerPort) int) errs.ValidationErrorList { </del> <ins> func AccumulateUniqueHostPorts(containers []api.Container, accumulator *util.StringSet) errs.ValidationErrorList { </ins> allErrs := errs.ValidationErrorList{} for ci, ctr := range containers { cErrs := errs.ValidationErrorList{} for pi := range ctr.Ports { <del> port := extract(&ctr.Ports[pi]) </del> <ins> port := ctr.Ports[pi].HostPort </ins> if port == 0 { continue } <del> if accumulator[port] { cErrs = append(cErrs, errs.NewFieldDuplicate("port", port)) </del> <ins> str := fmt.Sprintf("%d/%s", port, ctr.Ports[pi].Protocol) if accumulator.Has(str) { cErrs = append(cErrs, errs.NewFieldDuplicate("port", str)) </ins> } else { <del> accumulator[port] = true </del> <ins> accumulator.Insert(str) </ins> } } allErrs = append(allErrs, cErrs.PrefixIndex(ci)...)

// checkHostPortConflicts checks for colliding Port.HostPort values across // a slice of containers. func checkHostPortConflicts(containers []api.Container) errs.ValidationErrorList { <del> allPorts := map[int]bool{} return AccumulateUniquePorts(containers, allPorts, func(p *api.ContainerPort) int { return p.HostPort }) </del> <ins> allPorts := util.StringSet{} return AccumulateUniqueHostPorts(containers, &allPorts) </ins> } func validateExecAction(exec *api.ExecAction) errs.ValidationErrorList {

allErrs = append(allErrs, cErrs.PrefixIndex(i)...) } // Check for colliding ports across all containers. <del> // TODO(thockin): This really is dependent on the network config of the host (IP per pod?) // 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. </del> allErrs = append(allErrs, checkHostPortConflicts(containers)...) return allErrs

}, ImagePullPolicy: "IfNotPresent", }, <ins> { 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", }, </ins> {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)}, } if errs := validateContainers(successCase, volumes); len(errs) != 0 {

// checkHostPortConflicts detects pods with conflicted host ports. func checkHostPortConflicts(pods []*api.Pod) (fitting []*api.Pod, notFitting []*api.Pod) { <del> ports := map[int]bool{} extract := func(p *api.ContainerPort) int { return p.HostPort } </del> <ins> ports := util.StringSet{} </ins> // Respect the pod creation order when resolving conflicts. sort.Sort(podsByCreationTime(pods)) for _, pod := range pods { <del> if errs := validation.AccumulateUniquePorts(pod.Spec.Containers, ports, extract); len(errs) != 0 { </del> <ins> if errs := validation.AccumulateUniqueHostPorts(pod.Spec.Containers, &ports); len(errs) != 0 { </ins> glog.Errorf("Pod %q: HostPort is already allocated, ignoring: %v", kubecontainer.GetPodFullName(pod), errs) notFitting = append(notFitting, pod) continue