github.com/rootless-containers/rootlesskit/v2@v2.3.4/cmd/rootlessctl/port.go (about) 1 package main 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os" 9 "strconv" 10 "text/tabwriter" 11 12 "github.com/urfave/cli/v2" 13 14 "github.com/rootless-containers/rootlesskit/v2/pkg/port" 15 "github.com/rootless-containers/rootlesskit/v2/pkg/port/portutil" 16 ) 17 18 var listPortsCommand = cli.Command{ 19 Name: "list-ports", 20 Usage: "List ports", 21 ArgsUsage: "[flags]", 22 Flags: []cli.Flag{ 23 &cli.BoolFlag{ 24 Name: "json", 25 Usage: "Prints as JSON", 26 }, 27 }, 28 Action: listPortsAction, 29 } 30 31 func listPortsAction(clicontext *cli.Context) error { 32 c, err := newClient(clicontext) 33 if err != nil { 34 return err 35 } 36 pm := c.PortManager() 37 ctx := context.Background() 38 portStatuses, err := pm.ListPorts(ctx) 39 if err != nil { 40 return err 41 } 42 if clicontext.Bool("json") { 43 // Marshal per entry, for consistency with add-ports 44 // (and for potential streaming support) 45 for _, p := range portStatuses { 46 m, err := json.Marshal(p) 47 if err != nil { 48 return err 49 } 50 fmt.Println(string(m)) 51 } 52 return nil 53 } 54 w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0) 55 if _, err := fmt.Fprintln(w, "ID\tPROTO\tPARENTIP\tPARENTPORT\tCHILDIP\tCHILDPORT\t"); err != nil { 56 return err 57 } 58 for _, p := range portStatuses { 59 if _, err := fmt.Fprintf(w, "%d\t%s\t%s\t%d\t%s\t%d\t\n", 60 p.ID, p.Spec.Proto, p.Spec.ParentIP, p.Spec.ParentPort, p.Spec.ChildIP, p.Spec.ChildPort); err != nil { 61 return err 62 } 63 } 64 return w.Flush() 65 } 66 67 var addPortsCommand = cli.Command{ 68 Name: "add-ports", 69 Usage: "Add ports", 70 ArgsUsage: "[flags] PARENTIP:PARENTPORT:CHILDPORT/PROTO [PARENTIP:PARENTPORT:CHILDPORT/PROTO...]", 71 Description: "Add exposed ports. The port spec is similar to `docker run -p`. e.g. \"127.0.0.1:8080:80/tcp\".", 72 Flags: []cli.Flag{ 73 &cli.BoolFlag{ 74 Name: "json", 75 Usage: "Prints as JSON", 76 }, 77 }, 78 Action: addPortsAction, 79 } 80 81 func addPortsAction(clicontext *cli.Context) error { 82 if clicontext.NArg() < 1 { 83 return errors.New("no port specified") 84 } 85 var portSpecs []port.Spec 86 for _, s := range clicontext.Args().Slice() { 87 sp, err := portutil.ParsePortSpec(s) 88 if err != nil { 89 return err 90 } 91 portSpecs = append(portSpecs, *sp) 92 } 93 94 c, err := newClient(clicontext) 95 if err != nil { 96 return err 97 } 98 pm := c.PortManager() 99 ctx := context.Background() 100 for _, sp := range portSpecs { 101 portStatus, err := pm.AddPort(ctx, sp) 102 if err != nil { 103 return err 104 } 105 if clicontext.Bool("json") { 106 m, err := json.Marshal(portStatus) 107 if err != nil { 108 return err 109 } 110 fmt.Println(string(m)) 111 } else { 112 fmt.Printf("%d\n", portStatus.ID) 113 } 114 } 115 return nil 116 } 117 118 var removePortsCommand = cli.Command{ 119 Name: "remove-ports", 120 Usage: "Remove ports", 121 ArgsUsage: "[flags] ID [ID...]", 122 Action: removePortsAction, 123 } 124 125 func removePortsAction(clicontext *cli.Context) error { 126 if clicontext.NArg() < 1 { 127 return errors.New("no ID specified") 128 } 129 var ids []int 130 for _, s := range clicontext.Args().Slice() { 131 id, err := strconv.Atoi(s) 132 if err != nil { 133 return err 134 } 135 ids = append(ids, id) 136 } 137 c, err := newClient(clicontext) 138 if err != nil { 139 return err 140 } 141 pm := c.PortManager() 142 ctx := context.Background() 143 for _, id := range ids { 144 if err := pm.RemovePort(ctx, id); err != nil { 145 return err 146 } 147 fmt.Printf("%d\n", id) 148 } 149 return nil 150 }