mirror of https://github.com/docker/cli.git
Add support for host port PublishMode in services
Add api/cli support for adding host port PublishMode in services. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
7d89ba2d9d
commit
148dc157f6
|
@ -40,12 +40,14 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
flags.Var(&opts.constraints, flagConstraint, "Placement constraints")
|
||||
flags.Var(&opts.networks, flagNetwork, "Network attachments")
|
||||
flags.Var(&opts.secrets, flagSecret, "Specify secrets to expose to the service")
|
||||
flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port")
|
||||
flags.VarP(&opts.endpoint.publishPorts, flagPublish, "p", "Publish a port as a node port")
|
||||
flags.MarkHidden(flagPublish)
|
||||
flags.Var(&opts.groups, flagGroup, "Set one or more supplementary user groups for the container")
|
||||
flags.Var(&opts.dns, flagDNS, "Set custom DNS servers")
|
||||
flags.Var(&opts.dnsOption, flagDNSOption, "Set DNS options")
|
||||
flags.Var(&opts.dnsSearch, flagDNSSearch, "Set custom DNS search domains")
|
||||
flags.Var(&opts.hosts, flagHost, "Set one or more custom host-to-IP mappings (host:ip)")
|
||||
flags.Var(&opts.endpoint.expandedPorts, flagPort, "Publish a port")
|
||||
|
||||
flags.SetInterspersed(false)
|
||||
return cmd
|
||||
|
|
|
@ -287,14 +287,15 @@ func convertNetworks(networks []string) []swarm.NetworkAttachmentConfig {
|
|||
}
|
||||
|
||||
type endpointOptions struct {
|
||||
mode string
|
||||
ports opts.ListOpts
|
||||
mode string
|
||||
publishPorts opts.ListOpts
|
||||
expandedPorts opts.PortOpt
|
||||
}
|
||||
|
||||
func (e *endpointOptions) ToEndpointSpec() *swarm.EndpointSpec {
|
||||
portConfigs := []swarm.PortConfig{}
|
||||
// We can ignore errors because the format was already validated by ValidatePort
|
||||
ports, portBindings, _ := nat.ParsePortSpecs(e.ports.GetAll())
|
||||
ports, portBindings, _ := nat.ParsePortSpecs(e.publishPorts.GetAll())
|
||||
|
||||
for port := range ports {
|
||||
portConfigs = append(portConfigs, ConvertPortToPortConfig(port, portBindings)...)
|
||||
|
@ -302,7 +303,7 @@ func (e *endpointOptions) ToEndpointSpec() *swarm.EndpointSpec {
|
|||
|
||||
return &swarm.EndpointSpec{
|
||||
Mode: swarm.ResolutionMode(strings.ToLower(e.mode)),
|
||||
Ports: portConfigs,
|
||||
Ports: append(portConfigs, e.expandedPorts.Value()...),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -459,7 +460,7 @@ func newServiceOptions() *serviceOptions {
|
|||
env: opts.NewListOpts(runconfigopts.ValidateEnv),
|
||||
envFile: opts.NewListOpts(nil),
|
||||
endpoint: endpointOptions{
|
||||
ports: opts.NewListOpts(ValidatePort),
|
||||
publishPorts: opts.NewListOpts(ValidatePort),
|
||||
},
|
||||
groups: opts.NewListOpts(nil),
|
||||
logDriver: newLogDriverOptions(),
|
||||
|
@ -647,6 +648,9 @@ const (
|
|||
flagPublish = "publish"
|
||||
flagPublishRemove = "publish-rm"
|
||||
flagPublishAdd = "publish-add"
|
||||
flagPort = "port"
|
||||
flagPortAdd = "port-add"
|
||||
flagPortRemove = "port-rm"
|
||||
flagReplicas = "replicas"
|
||||
flagReserveCPU = "reserve-cpu"
|
||||
flagReserveMemory = "reserve-memory"
|
||||
|
|
|
@ -48,6 +48,8 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
flags.Var(newListOptsVar(), flagContainerLabelRemove, "Remove a container label by its key")
|
||||
flags.Var(newListOptsVar(), flagMountRemove, "Remove a mount by its target path")
|
||||
flags.Var(newListOptsVar(), flagPublishRemove, "Remove a published port by its target port")
|
||||
flags.MarkHidden(flagPublishRemove)
|
||||
flags.Var(newListOptsVar(), flagPortRemove, "Remove a port(target-port mandatory)")
|
||||
flags.Var(newListOptsVar(), flagConstraintRemove, "Remove a constraint")
|
||||
flags.Var(newListOptsVar(), flagDNSRemove, "Remove a custom DNS server")
|
||||
flags.Var(newListOptsVar(), flagDNSOptionRemove, "Remove a DNS option")
|
||||
|
@ -60,7 +62,9 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
flags.Var(&opts.secrets, flagSecretAdd, "Add or update a secret on a service")
|
||||
flags.Var(&opts.mounts, flagMountAdd, "Add or update a mount on a service")
|
||||
flags.Var(&opts.constraints, flagConstraintAdd, "Add or update a placement constraint")
|
||||
flags.Var(&opts.endpoint.ports, flagPublishAdd, "Add or update a published port")
|
||||
flags.Var(&opts.endpoint.publishPorts, flagPublishAdd, "Add or update a published port")
|
||||
flags.MarkHidden(flagPublishAdd)
|
||||
flags.Var(&opts.endpoint.expandedPorts, flagPortAdd, "Add or update a port")
|
||||
flags.Var(&opts.groups, flagGroupAdd, "Add an additional supplementary user group to the container")
|
||||
flags.Var(&opts.dns, flagDNSAdd, "Add or update a custom DNS server")
|
||||
flags.Var(&opts.dnsOption, flagDNSOptionAdd, "Add or update a DNS option")
|
||||
|
@ -267,7 +271,7 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
|
|||
}
|
||||
}
|
||||
|
||||
if anyChanged(flags, flagPublishAdd, flagPublishRemove) {
|
||||
if anyChanged(flags, flagPublishAdd, flagPublishRemove, flagPortAdd, flagPortRemove) {
|
||||
if spec.EndpointSpec == nil {
|
||||
spec.EndpointSpec = &swarm.EndpointSpec{}
|
||||
}
|
||||
|
@ -627,7 +631,13 @@ func portConfigToString(portConfig *swarm.PortConfig) string {
|
|||
if protocol == "" {
|
||||
protocol = "tcp"
|
||||
}
|
||||
return fmt.Sprintf("%v/%s", portConfig.PublishedPort, protocol)
|
||||
|
||||
mode := portConfig.PublishMode
|
||||
if mode == "" {
|
||||
mode = "ingress"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v:%v/%s/%s", portConfig.PublishedPort, portConfig.TargetPort, protocol, mode)
|
||||
}
|
||||
|
||||
func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error {
|
||||
|
@ -649,6 +659,15 @@ func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error {
|
|||
}
|
||||
}
|
||||
|
||||
if flags.Changed(flagPortAdd) {
|
||||
for _, entry := range flags.Lookup(flagPortAdd).Value.(*opts.PortOpt).Value() {
|
||||
if v, ok := portSet[portConfigToString(&entry)]; ok && v != entry {
|
||||
return fmt.Errorf("conflicting port mapping between %v:%v/%s and %v:%v/%s", entry.PublishedPort, entry.TargetPort, entry.Protocol, v.PublishedPort, v.TargetPort, v.Protocol)
|
||||
}
|
||||
portSet[portConfigToString(&entry)] = entry
|
||||
}
|
||||
}
|
||||
|
||||
// Override previous PortConfig in service if there is any duplicate
|
||||
for _, entry := range *portConfig {
|
||||
if _, ok := portSet[portConfigToString(&entry)]; !ok {
|
||||
|
@ -657,6 +676,14 @@ func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error {
|
|||
}
|
||||
|
||||
toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll()
|
||||
removePortCSV := flags.Lookup(flagPortRemove).Value.(*opts.ListOpts).GetAll()
|
||||
removePortOpts := &opts.PortOpt{}
|
||||
for _, portCSV := range removePortCSV {
|
||||
if err := removePortOpts.Set(portCSV); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
newPorts := []swarm.PortConfig{}
|
||||
portLoop:
|
||||
for _, port := range portSet {
|
||||
|
@ -666,14 +693,36 @@ portLoop:
|
|||
continue portLoop
|
||||
}
|
||||
}
|
||||
|
||||
for _, pConfig := range removePortOpts.Value() {
|
||||
if equalProtocol(port.Protocol, pConfig.Protocol) &&
|
||||
port.TargetPort == pConfig.TargetPort &&
|
||||
equalPublishMode(port.PublishMode, pConfig.PublishMode) {
|
||||
continue portLoop
|
||||
}
|
||||
}
|
||||
|
||||
newPorts = append(newPorts, port)
|
||||
}
|
||||
|
||||
// Sort the PortConfig to avoid unnecessary updates
|
||||
sort.Sort(byPortConfig(newPorts))
|
||||
*portConfig = newPorts
|
||||
return nil
|
||||
}
|
||||
|
||||
func equalProtocol(prot1, prot2 swarm.PortConfigProtocol) bool {
|
||||
return prot1 == prot2 ||
|
||||
(prot1 == swarm.PortConfigProtocol("") && prot2 == swarm.PortConfigProtocolTCP) ||
|
||||
(prot2 == swarm.PortConfigProtocol("") && prot1 == swarm.PortConfigProtocolTCP)
|
||||
}
|
||||
|
||||
func equalPublishMode(mode1, mode2 swarm.PortConfigPublishMode) bool {
|
||||
return mode1 == mode2 ||
|
||||
(mode1 == swarm.PortConfigPublishMode("") && mode2 == swarm.PortConfigPublishModeIngress) ||
|
||||
(mode2 == swarm.PortConfigPublishMode("") && mode1 == swarm.PortConfigPublishModeIngress)
|
||||
}
|
||||
|
||||
func equalPort(targetPort nat.Port, port swarm.PortConfig) bool {
|
||||
return (string(port.Protocol) == targetPort.Proto() &&
|
||||
port.TargetPort == uint32(targetPort.Int()))
|
||||
|
|
|
@ -238,7 +238,7 @@ func TestUpdatePortsDuplicateEntries(t *testing.T) {
|
|||
func TestUpdatePortsDuplicateKeys(t *testing.T) {
|
||||
// Test case for #25375
|
||||
flags := newUpdateCommand(nil).Flags()
|
||||
flags.Set("publish-add", "80:20")
|
||||
flags.Set("publish-add", "80:80")
|
||||
|
||||
portConfigs := []swarm.PortConfig{
|
||||
{TargetPort: 80, PublishedPort: 80},
|
||||
|
@ -247,21 +247,7 @@ func TestUpdatePortsDuplicateKeys(t *testing.T) {
|
|||
err := updatePorts(flags, &portConfigs)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(portConfigs), 1)
|
||||
assert.Equal(t, portConfigs[0].TargetPort, uint32(20))
|
||||
}
|
||||
|
||||
func TestUpdatePortsConflictingFlags(t *testing.T) {
|
||||
// Test case for #25375
|
||||
flags := newUpdateCommand(nil).Flags()
|
||||
flags.Set("publish-add", "80:80")
|
||||
flags.Set("publish-add", "80:20")
|
||||
|
||||
portConfigs := []swarm.PortConfig{
|
||||
{TargetPort: 80, PublishedPort: 80},
|
||||
}
|
||||
|
||||
err := updatePorts(flags, &portConfigs)
|
||||
assert.Error(t, err, "conflicting port mapping")
|
||||
assert.Equal(t, portConfigs[0].TargetPort, uint32(80))
|
||||
}
|
||||
|
||||
func TestUpdateHealthcheckTable(t *testing.T) {
|
||||
|
|
|
@ -17,10 +17,25 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
psTaskItemFmt = "%s\t%s\t%s\t%s\t%s %s ago\t%s\n"
|
||||
psTaskItemFmt = "%s\t%s\t%s\t%s\t%s %s ago\t%s\t%s\n"
|
||||
maxErrLength = 30
|
||||
)
|
||||
|
||||
type portStatus swarm.PortStatus
|
||||
|
||||
func (ps portStatus) String() string {
|
||||
if len(ps.Ports) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("*:%d->%d/%s", ps.Ports[0].PublishedPort, ps.Ports[0].TargetPort, ps.Ports[0].Protocol)
|
||||
for _, pConfig := range ps.Ports[1:] {
|
||||
str += fmt.Sprintf(",*:%d->%d/%s", pConfig.PublishedPort, pConfig.TargetPort, pConfig.Protocol)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
type tasksBySlot []swarm.Task
|
||||
|
||||
func (t tasksBySlot) Len() int {
|
||||
|
@ -51,7 +66,7 @@ func Print(dockerCli *command.DockerCli, ctx context.Context, tasks []swarm.Task
|
|||
|
||||
// Ignore flushing errors
|
||||
defer writer.Flush()
|
||||
fmt.Fprintln(writer, strings.Join([]string{"NAME", "IMAGE", "NODE", "DESIRED STATE", "CURRENT STATE", "ERROR"}, "\t"))
|
||||
fmt.Fprintln(writer, strings.Join([]string{"NAME", "IMAGE", "NODE", "DESIRED STATE", "CURRENT STATE", "ERROR", "PORTS"}, "\t"))
|
||||
|
||||
if err := print(writer, ctx, tasks, resolver, noTrunc); err != nil {
|
||||
return err
|
||||
|
@ -113,6 +128,7 @@ func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idr
|
|||
command.PrettyPrint(task.Status.State),
|
||||
strings.ToLower(units.HumanDuration(time.Since(task.Status.Timestamp))),
|
||||
taskErr,
|
||||
portStatus(task.Status.PortStatus),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
|
|
Loading…
Reference in New Issue