1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Make sure we validate simple syntax on service commands

We ignored errors for simple syntax in `PortOpt` (missed that in the
previous migration of this code). This make sure we don't ignore
`nat.Parse` errors.

Test has been migrate too (errors are not exactly the same as before
though -_-)

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2017-02-06 14:16:03 +01:00
parent 191719e39a
commit aa4ecd153b
No known key found for this signature in database
GPG key ID: 083CC6FD6EB699A3
5 changed files with 48 additions and 56 deletions

View file

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
runconfigopts "github.com/docker/docker/runconfig/opts" runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/docker/go-connections/nat"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -244,17 +243,6 @@ func (opts *healthCheckOptions) toHealthConfig() (*container.HealthConfig, error
return healthConfig, nil return healthConfig, nil
} }
// ValidatePort validates a string is in the expected format for a port definition
func ValidatePort(value string) (string, error) {
portMappings, err := nat.ParsePortSpec(value)
for _, portMapping := range portMappings {
if portMapping.Binding.HostIP != "" {
return "", fmt.Errorf("HostIP is not supported by a service.")
}
}
return value, err
}
// convertExtraHostsToSwarmHosts converts an array of extra hosts in cli // convertExtraHostsToSwarmHosts converts an array of extra hosts in cli
// <host>:<ip> // <host>:<ip>
// into a swarmkit host format: // into a swarmkit host format:

View file

@ -663,24 +663,6 @@ func portConfigToString(portConfig *swarm.PortConfig) string {
return fmt.Sprintf("%v:%v/%s/%s", portConfig.PublishedPort, portConfig.TargetPort, protocol, mode) return fmt.Sprintf("%v:%v/%s/%s", portConfig.PublishedPort, portConfig.TargetPort, protocol, mode)
} }
// FIXME(vdemeester) port to opts.PortOpt
// This validation is only used for `--publish-rm`.
// The `--publish-rm` takes:
// <TargetPort>[/<Protocol>] (e.g., 80, 80/tcp, 53/udp)
func validatePublishRemove(val string) (string, error) {
proto, port := nat.SplitProtoPort(val)
if proto != "tcp" && proto != "udp" {
return "", fmt.Errorf("invalid protocol '%s' for %s", proto, val)
}
if strings.Contains(port, ":") {
return "", fmt.Errorf("invalid port format: '%s', should be <TargetPort>[/<Protocol>] (e.g., 80, 80/tcp, 53/udp)", port)
}
if _, err := nat.ParsePort(port); err != nil {
return "", err
}
return val, nil
}
func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error { func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error {
// The key of the map is `port/protocol`, e.g., `80/tcp` // The key of the map is `port/protocol`, e.g., `80/tcp`
portSet := map[string]swarm.PortConfig{} portSet := map[string]swarm.PortConfig{}

View file

@ -362,29 +362,6 @@ func TestUpdatePortsRmWithProtocol(t *testing.T) {
assert.Equal(t, portConfigs[1].TargetPort, uint32(82)) assert.Equal(t, portConfigs[1].TargetPort, uint32(82))
} }
// FIXME(vdemeester) port to opts.PortOpt
func TestValidatePort(t *testing.T) {
validPorts := []string{"80/tcp", "80", "80/udp"}
invalidPorts := map[string]string{
"9999999": "out of range",
"80:80/tcp": "invalid port format",
"53:53/udp": "invalid port format",
"80:80": "invalid port format",
"80/xyz": "invalid protocol",
"tcp": "invalid syntax",
"udp": "invalid syntax",
"": "invalid protocol",
}
for _, port := range validPorts {
_, err := validatePublishRemove(port)
assert.Equal(t, err, nil)
}
for port, e := range invalidPorts {
_, err := validatePublishRemove(port)
assert.Error(t, err, e)
}
}
type secretAPIClientMock struct { type secretAPIClientMock struct {
listResult []swarm.Secret listResult []swarm.Secret
} }

View file

@ -94,11 +94,20 @@ func (p *PortOpt) Set(value string) error {
} else { } else {
// short syntax // short syntax
portConfigs := []swarm.PortConfig{} portConfigs := []swarm.PortConfig{}
// We can ignore errors because the format was already validated by ValidatePort ports, portBindingMap, err := nat.ParsePortSpecs([]string{value})
ports, portBindings, _ := nat.ParsePortSpecs([]string{value}) if err != nil {
return err
}
for _, portBindings := range portBindingMap {
for _, portBinding := range portBindings {
if portBinding.HostIP != "" {
return fmt.Errorf("HostIP is not supported.")
}
}
}
for port := range ports { for port := range ports {
portConfig, err := ConvertPortToPortConfig(port, portBindings) portConfig, err := ConvertPortToPortConfig(port, portBindingMap)
if err != nil { if err != nil {
return err return err
} }

View file

@ -245,6 +245,42 @@ func TestPortOptInvalidComplexSyntax(t *testing.T) {
} }
} }
func TestPortOptInvalidSimpleSyntax(t *testing.T) {
testCases := []struct {
value string
expectedError string
}{
{
value: "9999999",
expectedError: "Invalid containerPort: 9999999",
},
{
value: "80/xyz",
expectedError: "Invalid proto: xyz",
},
{
value: "tcp",
expectedError: "Invalid containerPort: tcp",
},
{
value: "udp",
expectedError: "Invalid containerPort: udp",
},
{
value: "",
expectedError: "No port specified",
},
{
value: "1.1.1.1:80:80",
expectedError: "HostIP is not supported",
},
}
for _, tc := range testCases {
var port PortOpt
assert.Error(t, port.Set(tc.value), tc.expectedError)
}
}
func assertContains(t *testing.T, portConfigs []swarm.PortConfig, expected swarm.PortConfig) { func assertContains(t *testing.T, portConfigs []swarm.PortConfig, expected swarm.PortConfig) {
var contains = false var contains = false
for _, portConfig := range portConfigs { for _, portConfig := range portConfigs {