■ ■ ■ ■ ■ ■
cmd/portforward/portforward.go
| skipped 17 lines |
18 | 18 | | "github.com/sirupsen/logrus" |
19 | 19 | | "github.com/spf13/cobra" |
20 | 20 | | |
21 | | - | "github.com/iximiuz/cdebug/pkg/cmd" |
| 21 | + | "github.com/iximiuz/cdebug/pkg/cliutil" |
| 22 | + | "github.com/iximiuz/cdebug/pkg/jsonutil" |
22 | 23 | | "github.com/iximiuz/cdebug/pkg/util" |
23 | 24 | | ) |
24 | 25 | | |
| skipped 18 lines |
43 | 44 | | |
44 | 45 | | const ( |
45 | 46 | | helperImage = "nixery.dev/shell/socat:latest" |
| 47 | + | |
| 48 | + | outFormatText = "text" |
| 49 | + | outFormatJSON = "json" |
46 | 50 | | ) |
47 | 51 | | |
48 | 52 | | type options struct { |
49 | 53 | | target string |
50 | 54 | | forwardings []string |
| 55 | + | output string |
| 56 | + | quiet bool |
51 | 57 | | } |
52 | 58 | | |
53 | | - | func NewCommand(cli cmd.CLI) *cobra.Command { |
| 59 | + | func NewCommand(cli cliutil.CLI) *cobra.Command { |
54 | 60 | | var opts options |
55 | 61 | | |
56 | 62 | | cmd := &cobra.Command{ |
| skipped 1 lines |
58 | 64 | | Short: `"Publish" one or more ports of an already running container`, |
59 | 65 | | Args: cobra.MinimumNArgs(2), |
60 | 66 | | RunE: func(cmd *cobra.Command, args []string) error { |
| 67 | + | cli.SetQuiet(opts.quiet) |
| 68 | + | |
61 | 69 | | opts.target = args[0] |
62 | 70 | | opts.forwardings = args[1:] |
63 | | - | return runPortForward(context.Background(), cli, &opts) |
| 71 | + | return cliutil.WrapStatusError(runPortForward(context.Background(), cli, &opts)) |
64 | 72 | | }, |
65 | 73 | | } |
66 | 74 | | |
| 75 | + | flags := cmd.Flags() |
| 76 | + | flags.SetInterspersed(false) // Instead of relying on -- |
| 77 | + | |
| 78 | + | flags.BoolVarP( |
| 79 | + | &opts.quiet, |
| 80 | + | "quiet", |
| 81 | + | "q", |
| 82 | + | false, |
| 83 | + | `Suppress verbose output`, |
| 84 | + | ) |
| 85 | + | |
| 86 | + | flags.StringVarP( |
| 87 | + | &opts.output, |
| 88 | + | "output", |
| 89 | + | "o", |
| 90 | + | outFormatText, |
| 91 | + | `Output format (plain text or JSON)`, |
| 92 | + | ) |
| 93 | + | |
67 | 94 | | return cmd |
68 | 95 | | } |
69 | 96 | | |
70 | | - | func runPortForward(ctx context.Context, cli cmd.CLI, opts *options) error { |
| 97 | + | func runPortForward(ctx context.Context, cli cliutil.CLI, opts *options) error { |
71 | 98 | | client, err := dockerclient.NewClientWithOpts( |
72 | 99 | | dockerclient.FromEnv, |
73 | 100 | | dockerclient.WithAPIVersionNegotiation(), |
| skipped 21 lines |
95 | 122 | | return err |
96 | 123 | | } |
97 | 124 | | |
98 | | - | fmt.Println("forwardings") |
99 | | - | util.PrettyPrint(forwardings) |
100 | | - | |
101 | | - | fmt.Println("forwardings.toDockerPortSpecs()") |
102 | | - | util.PrettyPrint(forwardings.toDockerPortSpecs()) |
103 | | - | |
104 | | - | fmt.Println("exposedPorts") |
105 | | - | util.PrettyPrint(exposedPorts) |
106 | | - | |
107 | | - | fmt.Println("portBindings") |
108 | | - | util.PrettyPrint(portBindings) |
109 | | - | |
110 | 125 | | // TODO: Iterate over all forwardings. |
111 | 126 | | resp, err := client.ContainerCreate( |
112 | 127 | | ctx, |
| skipped 26 lines |
139 | 154 | | if err != nil { |
140 | 155 | | return fmt.Errorf("cannot inspect forwarder container: %w", err) |
141 | 156 | | } |
| 157 | + | |
142 | 158 | | // TODO: Multi-network support. |
143 | 159 | | targetIP := target.NetworkSettings.Networks["bridge"].IPAddress |
144 | | - | for from, frontends := range forwarder.NetworkSettings.Ports { |
145 | | - | for _, frontend := range frontends { |
146 | | - | fmt.Printf("Forwarding %s to %s's %s:%s\n", net.JoinHostPort(frontend.HostIP, frontend.HostPort), target.Name[1:], targetIP, from) |
| 160 | + | for remotePort, localBindings := range forwarder.NetworkSettings.Ports { |
| 161 | + | for _, binding := range localBindings { |
| 162 | + | switch opts.output { |
| 163 | + | case outFormatText: |
| 164 | + | local := net.JoinHostPort(binding.HostIP, binding.HostPort) |
| 165 | + | remote := targetIP + ":" + string(remotePort) |
| 166 | + | cli.Say("Forwarding %s to %s's %s\n", local, target.Name[1:], remote) |
| 167 | + | case outFormatJSON: |
| 168 | + | cli.Say(jsonutil.Dump(map[string]string{ |
| 169 | + | "localHost": binding.HostIP, |
| 170 | + | "localPort": binding.HostPort, |
| 171 | + | "remoteHost": targetIP, |
| 172 | + | "remotePort": string(remotePort), |
| 173 | + | })) |
| 174 | + | default: |
| 175 | + | panic("unreachable!") |
| 176 | + | } |
147 | 177 | | } |
148 | 178 | | } |
149 | 179 | | |
| skipped 3 lines |
153 | 183 | | |
154 | 184 | | go func() { |
155 | 185 | | for _ = range sigCh { |
156 | | - | fmt.Println("Exiting...") |
| 186 | + | cli.Wisper("Exiting...") |
| 187 | + | |
157 | 188 | | if err := client.ContainerKill(ctx, resp.ID, "KILL"); err != nil { |
158 | | - | logrus.WithError(err).Warn("Cannot kill forwarder container") |
| 189 | + | logrus.Debugf("Cannot kill forwarder container: %s", err) |
159 | 190 | | } |
160 | 191 | | break |
161 | 192 | | } |
| skipped 14 lines |
176 | 207 | | |
177 | 208 | | func pullImage( |
178 | 209 | | ctx context.Context, |
179 | | - | cli cmd.CLI, |
| 210 | + | cli cliutil.CLI, |
180 | 211 | | client *dockerclient.Client, |
181 | 212 | | image string, |
182 | 213 | | ) error { |
| skipped 89 lines |