Merge pull request #581 from thaJeztah/better-port-range-printing
Improve presentation of published port ranges
This commit is contained in:
commit
fab4762941
@ -2,6 +2,7 @@ package formatter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -520,19 +521,95 @@ func (c *serviceContext) Image() string {
|
|||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type portRange struct {
|
||||||
|
pStart uint32
|
||||||
|
pEnd uint32
|
||||||
|
tStart uint32
|
||||||
|
tEnd uint32
|
||||||
|
protocol swarm.PortConfigProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr portRange) String() string {
|
||||||
|
var (
|
||||||
|
pub string
|
||||||
|
tgt string
|
||||||
|
)
|
||||||
|
|
||||||
|
if pr.pEnd > pr.pStart {
|
||||||
|
pub = fmt.Sprintf("%d-%d", pr.pStart, pr.pEnd)
|
||||||
|
} else {
|
||||||
|
pub = fmt.Sprintf("%d", pr.pStart)
|
||||||
|
}
|
||||||
|
if pr.tEnd > pr.tStart {
|
||||||
|
tgt = fmt.Sprintf("%d-%d", pr.tStart, pr.tEnd)
|
||||||
|
} else {
|
||||||
|
tgt = fmt.Sprintf("%d", pr.tStart)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("*:%s->%s/%s", pub, tgt, pr.protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ports formats published ports on the ingress network for output.
|
||||||
|
//
|
||||||
|
// Where possible, ranges are grouped to produce a compact output:
|
||||||
|
// - multiple ports mapped to a single port (80->80, 81->80); is formatted as *:80-81->80
|
||||||
|
// - multiple consecutive ports on both sides; (80->80, 81->81) are formatted as: *:80-81->80-81
|
||||||
|
//
|
||||||
|
// The above should not be grouped together, i.e.:
|
||||||
|
// - 80->80, 81->81, 82->80 should be presented as : *:80-81->80-81, *:82->80
|
||||||
|
//
|
||||||
|
// TODO improve:
|
||||||
|
// - combine non-consecutive ports mapped to a single port (80->80, 81->80, 84->80, 86->80, 87->80); to be printed as *:80-81,84,86-87->80
|
||||||
|
// - combine tcp and udp mappings if their port-mapping is exactly the same (*:80-81->80-81/tcp+udp instead of *:80-81->80-81/tcp, *:80-81->80-81/udp)
|
||||||
func (c *serviceContext) Ports() string {
|
func (c *serviceContext) Ports() string {
|
||||||
if c.service.Endpoint.Ports == nil {
|
if c.service.Endpoint.Ports == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pr := portRange{}
|
||||||
ports := []string{}
|
ports := []string{}
|
||||||
for _, pConfig := range c.service.Endpoint.Ports {
|
|
||||||
if pConfig.PublishMode == swarm.PortConfigPublishModeIngress {
|
sort.Sort(byProtocolAndPublishedPort(c.service.Endpoint.Ports))
|
||||||
ports = append(ports, fmt.Sprintf("*:%d->%d/%s",
|
|
||||||
pConfig.PublishedPort,
|
for _, p := range c.service.Endpoint.Ports {
|
||||||
pConfig.TargetPort,
|
if p.PublishMode == swarm.PortConfigPublishModeIngress {
|
||||||
pConfig.Protocol,
|
prIsRange := pr.tEnd != pr.tStart
|
||||||
))
|
tOverlaps := p.TargetPort <= pr.tEnd
|
||||||
|
|
||||||
|
// Start a new port-range if:
|
||||||
|
// - the protocol is different from the current port-range
|
||||||
|
// - published or target port are not consecutive to the current port-range
|
||||||
|
// - the current port-range is a _range_, and the target port overlaps with the current range's target-ports
|
||||||
|
if p.Protocol != pr.protocol || p.PublishedPort-pr.pEnd > 1 || p.TargetPort-pr.tEnd > 1 || prIsRange && tOverlaps {
|
||||||
|
// start a new port-range, and print the previous port-range (if any)
|
||||||
|
if pr.pStart > 0 {
|
||||||
|
ports = append(ports, pr.String())
|
||||||
|
}
|
||||||
|
pr = portRange{
|
||||||
|
pStart: p.PublishedPort,
|
||||||
|
pEnd: p.PublishedPort,
|
||||||
|
tStart: p.TargetPort,
|
||||||
|
tEnd: p.TargetPort,
|
||||||
|
protocol: p.Protocol,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pr.pEnd = p.PublishedPort
|
||||||
|
pr.tEnd = p.TargetPort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.Join(ports, ",")
|
if pr.pStart > 0 {
|
||||||
|
ports = append(ports, pr.String())
|
||||||
|
}
|
||||||
|
return strings.Join(ports, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
type byProtocolAndPublishedPort []swarm.PortConfig
|
||||||
|
|
||||||
|
func (a byProtocolAndPublishedPort) Len() int { return len(a) }
|
||||||
|
func (a byProtocolAndPublishedPort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a byProtocolAndPublishedPort) Less(i, j int) bool {
|
||||||
|
if a[i].Protocol == a[j].Protocol {
|
||||||
|
return a[i].PublishedPort < a[j].PublishedPort
|
||||||
|
}
|
||||||
|
return a[i].Protocol < a[j].Protocol
|
||||||
}
|
}
|
||||||
|
@ -224,3 +224,124 @@ func TestServiceContextWriteJSONField(t *testing.T) {
|
|||||||
assert.Equal(t, services[i].Spec.Name, s, msg)
|
assert.Equal(t, services[i].Spec.Name, s, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServiceContext_Ports(t *testing.T) {
|
||||||
|
c := serviceContext{
|
||||||
|
service: swarm.Service{
|
||||||
|
Endpoint: swarm.Endpoint{
|
||||||
|
Ports: []swarm.PortConfig{
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 80,
|
||||||
|
PublishedPort: 81,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 80,
|
||||||
|
PublishedPort: 80,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 95,
|
||||||
|
PublishedPort: 95,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 90,
|
||||||
|
PublishedPort: 90,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 91,
|
||||||
|
PublishedPort: 91,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 92,
|
||||||
|
PublishedPort: 92,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 93,
|
||||||
|
PublishedPort: 93,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 94,
|
||||||
|
PublishedPort: 94,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 95,
|
||||||
|
PublishedPort: 95,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 90,
|
||||||
|
PublishedPort: 90,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 96,
|
||||||
|
PublishedPort: 96,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 91,
|
||||||
|
PublishedPort: 91,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 92,
|
||||||
|
PublishedPort: 92,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 93,
|
||||||
|
PublishedPort: 93,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "udp",
|
||||||
|
TargetPort: 94,
|
||||||
|
PublishedPort: 94,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 60,
|
||||||
|
PublishedPort: 60,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 61,
|
||||||
|
PublishedPort: 61,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Protocol: "tcp",
|
||||||
|
TargetPort: 61,
|
||||||
|
PublishedPort: 62,
|
||||||
|
PublishMode: "ingress",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "*:60-61->60-61/tcp, *:62->61/tcp, *:80-81->80/tcp, *:90-95->90-95/tcp, *:90-96->90-96/udp", c.Ports())
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user