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
|
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/rootless-containers/rootlesskit/v2/pkg/api"
"github.com/rootless-containers/rootlesskit/v2/pkg/httputil"
"github.com/rootless-containers/rootlesskit/v2/pkg/port"
)
type Client interface {
HTTPClient() *http.Client
PortManager() port.Manager
Info(context.Context) (*api.Info, error)
}
// New creates a client.
// socketPath is a path to the UNIX socket, without unix:// prefix.
func New(socketPath string) (Client, error) {
hc, err := httputil.NewHTTPClient(socketPath)
if err != nil {
return nil, err
}
return NewWithHTTPClient(hc), nil
}
func NewWithHTTPClient(hc *http.Client) Client {
return &client{
Client: hc,
version: "v1",
dummyHost: "rootlesskit",
}
}
type client struct {
*http.Client
// version is always "v1"
// TODO(AkihiroSuda): negotiate the version
version string
dummyHost string
}
func (c *client) HTTPClient() *http.Client {
return c.Client
}
func (c *client) PortManager() port.Manager {
return &portManager{
client: c,
}
}
func (c *client) Info(ctx context.Context) (*api.Info, error) {
u := fmt.Sprintf("http://%s/%s/info", c.dummyHost, c.version)
req, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
resp, err := c.HTTPClient().Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if err := httputil.Successful(resp); err != nil {
return nil, err
}
var info api.Info
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&info); err != nil {
return nil, err
}
return &info, nil
}
type portManager struct {
*client
}
func (pm *portManager) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) {
m, err := json.Marshal(spec)
if err != nil {
return nil, err
}
u := fmt.Sprintf("http://%s/%s/ports", pm.client.dummyHost, pm.client.version)
req, err := http.NewRequest("POST", u, bytes.NewReader(m))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req = req.WithContext(ctx)
resp, err := pm.client.HTTPClient().Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if err := httputil.Successful(resp); err != nil {
return nil, err
}
dec := json.NewDecoder(resp.Body)
var status port.Status
if err := dec.Decode(&status); err != nil {
return nil, err
}
return &status, nil
}
func (pm *portManager) ListPorts(ctx context.Context) ([]port.Status, error) {
u := fmt.Sprintf("http://%s/%s/ports", pm.client.dummyHost, pm.client.version)
req, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
resp, err := pm.client.HTTPClient().Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if err := httputil.Successful(resp); err != nil {
return nil, err
}
var statuses []port.Status
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&statuses); err != nil {
return nil, err
}
return statuses, nil
}
func (pm *portManager) RemovePort(ctx context.Context, id int) error {
u := fmt.Sprintf("http://%s/%s/ports/%d", pm.client.dummyHost, pm.client.version, id)
req, err := http.NewRequest("DELETE", u, nil)
if err != nil {
return err
}
req = req.WithContext(ctx)
resp, err := pm.client.HTTPClient().Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if err := httputil.Successful(resp); err != nil {
return err
}
return nil
}
|