Skip to content

Commit cf510ea

Browse files
Merge pull request #17093 from coreydaley/bugzilla_1505558_expose_udp_dockerfile
Automatic merge from submit-queue (batch tested with PRs 17105, 17036, 17062, 17093). Allow EXPOSE <number>/<protocol> in Dockerfile
2 parents a324f1a + 78eb693 commit cf510ea

File tree

2 files changed

+92
-5
lines changed

2 files changed

+92
-5
lines changed

pkg/generate/app/cmd/newapp.go

+32-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
dockerfileparser "github.com/docker/docker/builder/dockerfile/parser"
14+
"github.com/docker/go-connections/nat"
1415
"github.com/fsouza/go-dockerclient"
1516
"github.com/golang/glog"
1617

@@ -1100,7 +1101,7 @@ func optionallyValidateExposedPorts(config *AppConfig, repositories app.SourceRe
11001101
for _, repo := range repositories {
11011102
if repoInfo := repo.Info(); repoInfo != nil && repoInfo.Dockerfile != nil {
11021103
node := repoInfo.Dockerfile.AST()
1103-
if err := exposedPortsAreNumeric(node); err != nil {
1104+
if err := exposedPortsAreValid(node); err != nil {
11041105
return fmt.Errorf("the Dockerfile has an invalid EXPOSE instruction: %v", err)
11051106
}
11061107
}
@@ -1109,11 +1110,38 @@ func optionallyValidateExposedPorts(config *AppConfig, repositories app.SourceRe
11091110
return nil
11101111
}
11111112

1112-
func exposedPortsAreNumeric(node *dockerfileparser.Node) error {
1113+
func exposedPortsAreValid(node *dockerfileparser.Node) error {
1114+
allErrs := make([]error, 0)
1115+
11131116
for _, port := range dockerfileutil.LastExposedPorts(node) {
1114-
if _, err := strconv.ParseInt(port, 10, 32); err != nil {
1115-
return fmt.Errorf("could not parse %q: must be numeric", port)
1117+
errs := make([]string, 0)
1118+
1119+
if strings.HasPrefix(port, "$") {
1120+
errs = append(errs, "args are not supported for port numbers")
1121+
}
1122+
1123+
proto, port := nat.SplitProtoPort(port)
1124+
1125+
_, err := strconv.ParseUint(port, 10, 16)
1126+
if err != nil {
1127+
if numError, ok := err.(*strconv.NumError); ok {
1128+
if numError.Err == strconv.ErrRange || numError.Err == strconv.ErrSyntax {
1129+
errs = append(errs, "port number must be in range 0 - 65535")
1130+
}
1131+
}
1132+
}
1133+
if len(proto) > 0 && !(strings.ToLower(proto) == "tcp" || strings.ToLower(proto) == "udp") {
1134+
errs = append(errs, "protocol must be tcp or udp")
11161135
}
1136+
if len(errs) > 0 {
1137+
allErrs = append(allErrs, fmt.Errorf("could not parse %q: [%v]", port, strings.Join(errs, ", ")))
1138+
}
1139+
11171140
}
1141+
1142+
if len(allErrs) > 0 {
1143+
return kutilerrors.NewAggregate(allErrs)
1144+
}
1145+
11181146
return nil
11191147
}

pkg/generate/app/cmd/newapp_test.go

+60-1
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,66 @@ func TestDisallowedNonNumericExposedPorts(t *testing.T) {
609609
if err == nil {
610610
t.Error("Expected error wasn't returned")
611611

612-
} else if !strings.Contains(err.Error(), "invalid EXPOSE") || !strings.Contains(err.Error(), "must be numeric") {
612+
} else if !strings.Contains(err.Error(), "args are not supported for port numbers") {
613+
t.Errorf("Unexpected error: %v", err)
614+
}
615+
}
616+
}
617+
618+
func TestExposedPortsAreValid(t *testing.T) {
619+
tests := []struct {
620+
dockerfile string
621+
expectedError string
622+
}{
623+
{
624+
dockerfile: "FROM centos\nEXPOSE 8080\nEXPOSE 8443",
625+
expectedError: "",
626+
},
627+
{
628+
dockerfile: "FROM centos\nEXPOSE 8080/tcp\nEXPOSE 8443/udp",
629+
expectedError: "",
630+
},
631+
{
632+
dockerfile: "FROM centos\nEXPOSE 808080",
633+
expectedError: "port number must be in range 0 - 65535",
634+
},
635+
{
636+
dockerfile: "FROM centos\nEXPOSE -1",
637+
expectedError: "port number must be in range 0 - 65535",
638+
},
639+
{
640+
dockerfile: "FROM centos\nEXPOSE 808080/tcp",
641+
expectedError: "port number must be in range 0 - 65535",
642+
},
643+
{
644+
dockerfile: "FROM centos\nEXPOSE -1/udp",
645+
expectedError: "port number must be in range 0 - 65535",
646+
},
647+
{
648+
dockerfile: "FROM centos\nARG PORT=8080\nEXPOSE $PORT",
649+
expectedError: "args are not supported for port numbers",
650+
},
651+
{
652+
dockerfile: "FROM centos\nEXPOSE 8080/xyz",
653+
expectedError: "protocol must be tcp or udp",
654+
},
655+
}
656+
657+
for _, test := range tests {
658+
config := &AppConfig{}
659+
config.Strategy = generate.StrategyDocker
660+
config.AllowNonNumericExposedPorts = false
661+
662+
repo, err := app.NewSourceRepositoryForDockerfile(test.dockerfile)
663+
if err != nil {
664+
t.Fatalf("Unexpected error during setup: %v", err)
665+
}
666+
repos := app.SourceRepositories{repo}
667+
668+
err = optionallyValidateExposedPorts(config, repos)
669+
if err == nil && test.expectedError == "" {
670+
continue
671+
} else if !strings.Contains(err.Error(), test.expectedError) {
613672
t.Errorf("Unexpected error: %v", err)
614673
}
615674
}

0 commit comments

Comments
 (0)