-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
port.go
155 lines (143 loc) · 4.17 KB
/
port.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package containers
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/containers/podman/v5/cmd/podman/common"
"github.com/containers/podman/v5/cmd/podman/registry"
"github.com/containers/podman/v5/cmd/podman/validate"
"github.com/containers/podman/v5/pkg/domain/entities"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
var (
portDescription = `List port mappings for the CONTAINER, or look up the public-facing port that is NAT-ed to the PRIVATE_PORT
`
portCommand = &cobra.Command{
Use: "port [options] CONTAINER [PORT]",
Short: "List port mappings or a specific mapping for the container",
Long: portDescription,
RunE: port,
Args: func(cmd *cobra.Command, args []string) error {
return validate.CheckAllLatestAndIDFile(cmd, args, true, "")
},
ValidArgsFunction: common.AutocompleteContainerOneArg,
Example: `podman port --all
podman port ctrID 80/tcp`,
}
containerPortCommand = &cobra.Command{
Use: "port [options] CONTAINER [PORT]",
Short: portCommand.Short,
Long: portDescription,
RunE: portCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
return validate.CheckAllLatestAndIDFile(cmd, args, true, "")
},
ValidArgsFunction: portCommand.ValidArgsFunction,
Example: `podman container port --all
podman container port CTRID 80`,
}
)
var (
portOpts entities.ContainerPortOptions
)
func portFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&portOpts.All, "all", "a", false, "Display port information for all containers")
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: portCommand,
})
portFlags(portCommand.Flags())
validate.AddLatestFlag(portCommand, &portOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: containerPortCommand,
Parent: containerCmd,
})
portFlags(containerPortCommand.Flags())
validate.AddLatestFlag(containerPortCommand, &portOpts.Latest)
}
func port(_ *cobra.Command, args []string) error {
var (
container string
err error
userPort uint16
userProto string
)
if len(args) == 0 && !portOpts.Latest && !portOpts.All {
return errors.New("you must supply a running container name or id")
}
if !portOpts.Latest && len(args) >= 1 {
container = strings.TrimPrefix(args[0], "/")
}
port := ""
if len(args) > 2 {
return errors.New("`port` accepts at most 2 arguments")
}
if len(args) > 1 && !portOpts.Latest {
port = args[1]
}
if len(args) == 1 && portOpts.Latest {
port = args[0]
}
if len(port) > 0 {
fields := strings.Split(port, "/")
if len(fields) > 2 || len(fields) < 1 {
return fmt.Errorf("port formats are port/protocol. '%s' is invalid", port)
}
if len(fields) == 1 {
fields = append(fields, "tcp")
}
portNum, err := strconv.ParseUint(fields[0], 10, 16)
if err != nil {
return err
}
userPort = uint16(portNum)
userProto = fields[1]
}
reports, err := registry.ContainerEngine().ContainerPort(registry.GetContext(), container, portOpts)
if err != nil {
return err
}
var found bool
// Iterate mappings
for _, report := range reports {
allPrefix := ""
if portOpts.All {
allPrefix = report.Id[:12] + "\t"
}
for _, v := range report.Ports {
hostIP := v.HostIP
// Set host IP to 0.0.0.0 if blank
if hostIP == "" {
hostIP = "0.0.0.0"
}
protocols := strings.Split(v.Protocol, ",")
for _, protocol := range protocols {
// If not searching by port or port/proto, then dump what we see
if port == "" {
for i := uint16(0); i < v.Range; i++ {
fmt.Printf("%s%d/%s -> %s:%d\n", allPrefix, v.ContainerPort+i, protocol, hostIP, v.HostPort+i)
}
continue
}
// check if the proto matches and if the port is in the range
// this is faster than looping over the range for no reason
if v.Protocol == userProto &&
v.ContainerPort <= userPort &&
v.ContainerPort+v.Range > userPort {
// we have to add the current range to the host port
hostPort := v.HostPort + userPort - v.ContainerPort
fmt.Printf("%s%s:%d\n", allPrefix, hostIP, hostPort)
found = true
break
}
}
}
if !found && port != "" {
return fmt.Errorf("failed to find published port %q", port)
}
}
return nil
}