diff --git a/Makefile b/Makefile index c8b24ebdf..66a17de7b 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,7 @@ build-and-e2e-compose-standalone: build e2e-compose-standalone ## Compile the co .PHONY: mocks mocks: + mockgen --version >/dev/null 2>&1 || go install github.com/golang/mock/mockgen@v1.6.0 mockgen -destination pkg/mocks/mock_docker_cli.go -package mocks github.com/docker/cli/cli/command Cli mockgen -destination pkg/mocks/mock_docker_api.go -package mocks github.com/docker/docker/client APIClient mockgen -destination pkg/mocks/mock_docker_compose_api.go -package mocks -source=./pkg/api/api.go Service diff --git a/cmd/compose/port.go b/cmd/compose/port.go index 59e61f491..e415bdc56 100644 --- a/cmd/compose/port.go +++ b/cmd/compose/port.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "strconv" + "strings" "github.com/spf13/cobra" @@ -28,7 +29,7 @@ import ( type portOptions struct { *projectOptions - port int + port uint16 protocol string index int } @@ -42,11 +43,12 @@ func portCommand(p *projectOptions, backend api.Service) *cobra.Command { Short: "Print the public port for a port binding.", Args: cobra.MinimumNArgs(2), PreRunE: Adapt(func(ctx context.Context, args []string) error { - port, err := strconv.Atoi(args[1]) + port, err := strconv.ParseUint(args[1], 10, 16) if err != nil { return err } - opts.port = port + opts.port = uint16(port) + opts.protocol = strings.ToLower(opts.protocol) return nil }), RunE: Adapt(func(ctx context.Context, args []string) error { diff --git a/pkg/api/api.go b/pkg/api/api.go index 8494b6549..5096e5920 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -72,7 +72,7 @@ type Service interface { // Events executes the equivalent to a `compose events` Events(ctx context.Context, projectName string, options EventsOptions) error // Port executes the equivalent to a `compose port` - Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error) + Port(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (string, int, error) // Images executes the equivalent of a `compose images` Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error) } diff --git a/pkg/api/proxy.go b/pkg/api/proxy.go index d023714bf..aa2364b74 100644 --- a/pkg/api/proxy.go +++ b/pkg/api/proxy.go @@ -48,7 +48,7 @@ type ServiceProxy struct { UnPauseFn func(ctx context.Context, project string, options PauseOptions) error TopFn func(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error) EventsFn func(ctx context.Context, project string, options EventsOptions) error - PortFn func(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) + PortFn func(ctx context.Context, project string, service string, port uint16, options PortOptions) (string, int, error) ImagesFn func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error) interceptors []Interceptor } @@ -294,7 +294,7 @@ func (s *ServiceProxy) Events(ctx context.Context, projectName string, options E } // Port implements Service interface -func (s *ServiceProxy) Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error) { +func (s *ServiceProxy) Port(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (string, int, error) { if s.PortFn == nil { return "", 0, ErrNotImplemented } diff --git a/pkg/compose/port.go b/pkg/compose/port.go index cc96f4cd2..5c57a334b 100644 --- a/pkg/compose/port.go +++ b/pkg/compose/port.go @@ -27,7 +27,7 @@ import ( "github.com/docker/docker/api/types/filters" ) -func (s *composeService) Port(ctx context.Context, projectName string, service string, port int, options api.PortOptions) (string, int, error) { +func (s *composeService) Port(ctx context.Context, projectName string, service string, port uint16, options api.PortOptions) (string, int, error) { projectName = strings.ToLower(projectName) list, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( @@ -44,9 +44,23 @@ func (s *composeService) Port(ctx context.Context, projectName string, service s } container := list[0] for _, p := range container.Ports { - if p.PrivatePort == uint16(port) && p.Type == options.Protocol { + if p.PrivatePort == port && p.Type == options.Protocol { return p.IP, int(p.PublicPort), nil } } - return "", 0, err + return "", 0, portNotFoundError(options.Protocol, port, container) +} + +func portNotFoundError(protocol string, port uint16, ctr moby.Container) error { + formatPort := func(protocol string, port uint16) string { + return fmt.Sprintf("%d/%s", port, protocol) + } + + var containerPorts []string + for _, p := range ctr.Ports { + containerPorts = append(containerPorts, formatPort(p.Type, p.PublicPort)) + } + + name := strings.TrimPrefix(ctr.Names[0], "/") + return fmt.Errorf("no port %s for container %s: %s", formatPort(protocol, port), name, strings.Join(containerPorts, ", ")) } diff --git a/pkg/mocks/mock_docker_compose_api.go b/pkg/mocks/mock_docker_compose_api.go index 16fd5781d..6569ccc64 100644 --- a/pkg/mocks/mock_docker_compose_api.go +++ b/pkg/mocks/mock_docker_compose_api.go @@ -209,7 +209,7 @@ func (mr *MockServiceMockRecorder) Pause(ctx, projectName, options interface{}) } // Port mocks base method. -func (m *MockService) Port(ctx context.Context, projectName, service string, port int, options api.PortOptions) (string, int, error) { +func (m *MockService) Port(ctx context.Context, projectName, service string, port uint16, options api.PortOptions) (string, int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Port", ctx, projectName, service, port, options) ret0, _ := ret[0].(string)