github.com/rootless-containers/rootlesskit/v2@v2.3.4/pkg/api/client/client.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "net/http" 9 10 "github.com/rootless-containers/rootlesskit/v2/pkg/api" 11 "github.com/rootless-containers/rootlesskit/v2/pkg/httputil" 12 "github.com/rootless-containers/rootlesskit/v2/pkg/port" 13 ) 14 15 type Client interface { 16 HTTPClient() *http.Client 17 PortManager() port.Manager 18 Info(context.Context) (*api.Info, error) 19 } 20 21 // New creates a client. 22 // socketPath is a path to the UNIX socket, without unix:// prefix. 23 func New(socketPath string) (Client, error) { 24 hc, err := httputil.NewHTTPClient(socketPath) 25 if err != nil { 26 return nil, err 27 } 28 return NewWithHTTPClient(hc), nil 29 } 30 31 func NewWithHTTPClient(hc *http.Client) Client { 32 return &client{ 33 Client: hc, 34 version: "v1", 35 dummyHost: "rootlesskit", 36 } 37 } 38 39 type client struct { 40 *http.Client 41 // version is always "v1" 42 // TODO(AkihiroSuda): negotiate the version 43 version string 44 dummyHost string 45 } 46 47 func (c *client) HTTPClient() *http.Client { 48 return c.Client 49 } 50 51 func (c *client) PortManager() port.Manager { 52 return &portManager{ 53 client: c, 54 } 55 } 56 57 func (c *client) Info(ctx context.Context) (*api.Info, error) { 58 u := fmt.Sprintf("http://%s/%s/info", c.dummyHost, c.version) 59 req, err := http.NewRequest("GET", u, nil) 60 if err != nil { 61 return nil, err 62 } 63 req = req.WithContext(ctx) 64 resp, err := c.HTTPClient().Do(req) 65 if err != nil { 66 return nil, err 67 } 68 defer resp.Body.Close() 69 if err := httputil.Successful(resp); err != nil { 70 return nil, err 71 } 72 var info api.Info 73 dec := json.NewDecoder(resp.Body) 74 if err := dec.Decode(&info); err != nil { 75 return nil, err 76 } 77 return &info, nil 78 } 79 80 type portManager struct { 81 *client 82 } 83 84 func (pm *portManager) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) { 85 m, err := json.Marshal(spec) 86 if err != nil { 87 return nil, err 88 } 89 u := fmt.Sprintf("http://%s/%s/ports", pm.client.dummyHost, pm.client.version) 90 req, err := http.NewRequest("POST", u, bytes.NewReader(m)) 91 if err != nil { 92 return nil, err 93 } 94 req.Header.Set("Content-Type", "application/json") 95 req = req.WithContext(ctx) 96 resp, err := pm.client.HTTPClient().Do(req) 97 if err != nil { 98 return nil, err 99 } 100 defer resp.Body.Close() 101 if err := httputil.Successful(resp); err != nil { 102 return nil, err 103 } 104 dec := json.NewDecoder(resp.Body) 105 var status port.Status 106 if err := dec.Decode(&status); err != nil { 107 return nil, err 108 } 109 return &status, nil 110 } 111 func (pm *portManager) ListPorts(ctx context.Context) ([]port.Status, error) { 112 u := fmt.Sprintf("http://%s/%s/ports", pm.client.dummyHost, pm.client.version) 113 req, err := http.NewRequest("GET", u, nil) 114 if err != nil { 115 return nil, err 116 } 117 req = req.WithContext(ctx) 118 resp, err := pm.client.HTTPClient().Do(req) 119 if err != nil { 120 return nil, err 121 } 122 defer resp.Body.Close() 123 if err := httputil.Successful(resp); err != nil { 124 return nil, err 125 } 126 var statuses []port.Status 127 dec := json.NewDecoder(resp.Body) 128 if err := dec.Decode(&statuses); err != nil { 129 return nil, err 130 } 131 return statuses, nil 132 } 133 func (pm *portManager) RemovePort(ctx context.Context, id int) error { 134 u := fmt.Sprintf("http://%s/%s/ports/%d", pm.client.dummyHost, pm.client.version, id) 135 req, err := http.NewRequest("DELETE", u, nil) 136 if err != nil { 137 return err 138 } 139 req = req.WithContext(ctx) 140 resp, err := pm.client.HTTPClient().Do(req) 141 if err != nil { 142 return err 143 } 144 defer resp.Body.Close() 145 if err := httputil.Successful(resp); err != nil { 146 return err 147 } 148 return nil 149 }