You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
watchtower/vendor/github.com/samalba/dockerclient/dockerclient.go

1026 lines
25 KiB
Go

package dockerclient
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"sync/atomic"
"time"
)
var _ Client = (*DockerClient)(nil)
const (
// APIVersion is currently hardcoded to v1.15
// TODO: bump the API version or allow users to choose which API version to
// use the client with. The current value does not make sense for many
// methods, such as ContainerStats, StartMonitorStats, and StopAllMonitorStats
// (v1.17) and
// ListVolumes, {Remove,Create}Volume, ListNetworks,
// {Inspect,Create,Connect,Disconnect,Remove}Network (v1.21)
APIVersion = "v1.15"
)
var (
ErrImageNotFound = errors.New("Image not found")
ErrNotFound = errors.New("Not found")
ErrConnectionRefused = errors.New("Cannot connect to the docker engine endpoint")
defaultTimeout = 30 * time.Second
)
type DockerClient struct {
URL *url.URL
HTTPClient *http.Client
TLSConfig *tls.Config
monitorStats int32
eventStopChan chan (struct{})
}
type Error struct {
StatusCode int
Status string
msg string
}
func (e Error) Error() string {
return fmt.Sprintf("%s: %s", e.Status, e.msg)
}
func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) {
return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout), nil)
}
func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration, setUserTimeout tcpFunc) (*DockerClient, error) {
u, err := url.Parse(daemonUrl)
if err != nil {
return nil, err
}
if u.Scheme == "" || u.Scheme == "tcp" {
if tlsConfig == nil {
u.Scheme = "http"
} else {
u.Scheme = "https"
}
}
httpClient := newHTTPClient(u, tlsConfig, timeout, setUserTimeout)
return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil
}
func (client *DockerClient) doRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) {
b := bytes.NewBuffer(body)
reader, err := client.doStreamRequest(method, path, b, headers)
if err != nil {
return nil, err
}
defer reader.Close()
data, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
return data, nil
}
func (client *DockerClient) doStreamRequest(method string, path string, in io.Reader, headers map[string]string) (io.ReadCloser, error) {
if (method == "POST" || method == "PUT") && in == nil {
in = bytes.NewReader(nil)
}
req, err := http.NewRequest(method, client.URL.String()+path, in)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/json")
if headers != nil {
for header, value := range headers {
req.Header.Add(header, value)
}
}
resp, err := client.HTTPClient.Do(req)
if err != nil {
if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil {
return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
}
if strings.Contains(err.Error(), "connection refused") {
return nil, ErrConnectionRefused
}
return nil, err
}
if resp.StatusCode == 404 {
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, ErrNotFound
}
if len(data) > 0 {
// check if is image not found error
if strings.Index(string(data), "No such image") != -1 {
return nil, ErrImageNotFound
}
return nil, errors.New(string(data))
}
return nil, ErrNotFound
}
if resp.StatusCode >= 400 {
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return nil, Error{StatusCode: resp.StatusCode, Status: resp.Status, msg: string(data)}
}
return resp.Body, nil
}
func (client *DockerClient) Info() (*Info, error) {
uri := fmt.Sprintf("/%s/info", APIVersion)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
ret := &Info{}
err = json.Unmarshal(data, &ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (client *DockerClient) ListContainers(all bool, size bool, filters string) ([]Container, error) {
argAll := 0
if all == true {
argAll = 1
}
showSize := 0
if size == true {
showSize = 1
}
uri := fmt.Sprintf("/%s/containers/json?all=%d&size=%d", APIVersion, argAll, showSize)
if filters != "" {
uri += "&filters=" + filters
}
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
ret := []Container{}
err = json.Unmarshal(data, &ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
uri := fmt.Sprintf("/%s/containers/%s/json", APIVersion, id)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
info := &ContainerInfo{}
err = json.Unmarshal(data, info)
if err != nil {
return nil, err
}
return info, nil
}
func (client *DockerClient) CreateContainer(config *ContainerConfig, name string, auth *AuthConfig) (string, error) {
data, err := json.Marshal(config)
if err != nil {
return "", err
}
uri := fmt.Sprintf("/%s/containers/create", APIVersion)
if name != "" {
v := url.Values{}
v.Set("name", name)
uri = fmt.Sprintf("%s?%s", uri, v.Encode())
}
headers := map[string]string{}
if auth != nil {
encoded_auth, err := auth.encode()
if err != nil {
return "", err
}
headers["X-Registry-Auth"] = encoded_auth
}
data, err = client.doRequest("POST", uri, data, headers)
if err != nil {
return "", err
}
result := &RespContainersCreate{}
err = json.Unmarshal(data, result)
if err != nil {
return "", fmt.Errorf(string(data))
}
return result.Id, nil
}
func (client *DockerClient) ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error) {
v := url.Values{}
v.Add("follow", strconv.FormatBool(options.Follow))
v.Add("stdout", strconv.FormatBool(options.Stdout))
v.Add("stderr", strconv.FormatBool(options.Stderr))
v.Add("timestamps", strconv.FormatBool(options.Timestamps))
if options.Tail > 0 {
v.Add("tail", strconv.FormatInt(options.Tail, 10))
}
uri := fmt.Sprintf("/%s/containers/%s/logs?%s", APIVersion, id, v.Encode())
req, err := http.NewRequest("GET", client.URL.String()+uri, nil)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/json")
resp, err := client.HTTPClient.Do(req)
if err != nil {
return nil, err
}
return resp.Body, nil
}
func (client *DockerClient) ContainerChanges(id string) ([]*ContainerChanges, error) {
uri := fmt.Sprintf("/%s/containers/%s/changes", APIVersion, id)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
changes := []*ContainerChanges{}
err = json.Unmarshal(data, &changes)
if err != nil {
return nil, err
}
return changes, nil
}
func (client *DockerClient) ContainerStats(id string, stopChan <-chan struct{}) (<-chan StatsOrError, error) {
uri := fmt.Sprintf("/%s/containers/%s/stats", APIVersion, id)
resp, err := client.HTTPClient.Get(client.URL.String() + uri)
if err != nil {
return nil, err
}
decode := func(decoder *json.Decoder) decodingResult {
var containerStats Stats
if err := decoder.Decode(&containerStats); err != nil {
return decodingResult{err: err}
} else {
return decodingResult{result: containerStats}
}
}
decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
statsOrErrorChan := make(chan StatsOrError)
go func() {
for decodingResult := range decodingResultChan {
stats, _ := decodingResult.result.(Stats)
statsOrErrorChan <- StatsOrError{
Stats: stats,
Error: decodingResult.err,
}
}
close(statsOrErrorChan)
}()
return statsOrErrorChan, nil
}
func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*json.Decoder) decodingResult, stopChan <-chan struct{}) <-chan decodingResult {
resultChan := make(chan decodingResult)
go func() {
decodeChan := make(chan decodingResult)
go func() {
decoder := json.NewDecoder(stream)
for {
decodeResult := decode(decoder)
decodeChan <- decodeResult
if decodeResult.err != nil {
close(decodeChan)
return
}
}
}()
defer close(resultChan)
for {
select {
case <-stopChan:
stream.Close()
for range decodeChan {
}
return
case decodeResult := <-decodeChan:
resultChan <- decodeResult
if decodeResult.err != nil {
stream.Close()
return
}
}
}
}()
return resultChan
}
func (client *DockerClient) ExecCreate(config *ExecConfig) (string, error) {
data, err := json.Marshal(config)
if err != nil {
return "", err
}
uri := fmt.Sprintf("/%s/containers/%s/exec", APIVersion, config.Container)
resp, err := client.doRequest("POST", uri, data, nil)
if err != nil {
return "", err
}
var createExecResp struct {
Id string
}
if err = json.Unmarshal(resp, &createExecResp); err != nil {
return "", err
}
return createExecResp.Id, nil
}
func (client *DockerClient) ExecStart(id string, config *ExecConfig) error {
data, err := json.Marshal(config)
if err != nil {
return err
}
uri := fmt.Sprintf("/%s/exec/%s/start", APIVersion, id)
if _, err := client.doRequest("POST", uri, data, nil); err != nil {
return err
}
return nil
}
func (client *DockerClient) ExecResize(id string, width, height int) error {
v := url.Values{}
w := strconv.Itoa(width)
h := strconv.Itoa(height)
v.Set("w", w)
v.Set("h", h)
uri := fmt.Sprintf("/%s/exec/%s/resize?%s", APIVersion, id, v.Encode())
if _, err := client.doRequest("POST", client.URL.String()+uri, nil, nil); err != nil {
return err
}
return nil
}
func (client *DockerClient) AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error) {
v := url.Values{}
if options != nil {
if options.Logs {
v.Set("logs", "1")
}
if options.Stream {
v.Set("stream", "1")
}
if options.Stdin {
v.Set("stdin", "1")
}
if options.Stdout {
v.Set("stdout", "1")
}
if options.Stderr {
v.Set("stderr", "1")
}
}
uri := fmt.Sprintf("/%s/containers/%s/attach?%s", APIVersion, id, v.Encode())
return client.doStreamRequest("POST", uri, nil, nil)
}
func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
data, err := json.Marshal(config)
if err != nil {
return err
}
uri := fmt.Sprintf("/%s/containers/%s/start", APIVersion, id)
_, err = client.doRequest("POST", uri, data, nil)
if err != nil {
return err
}
return nil
}
func (client *DockerClient) StopContainer(id string, timeout int) error {
uri := fmt.Sprintf("/%s/containers/%s/stop?t=%d", APIVersion, id, timeout)
_, err := client.doRequest("POST", uri, nil, nil)
if err != nil {
return err
}
return nil
}
func (client *DockerClient) RestartContainer(id string, timeout int) error {
uri := fmt.Sprintf("/%s/containers/%s/restart?t=%d", APIVersion, id, timeout)
_, err := client.doRequest("POST", uri, nil, nil)
if err != nil {
return err
}
return nil
}
func (client *DockerClient) KillContainer(id, signal string) error {
uri := fmt.Sprintf("/%s/containers/%s/kill?signal=%s", APIVersion, id, signal)
_, err := client.doRequest("POST", uri, nil, nil)
if err != nil {
return err
}
return nil
}
func (client *DockerClient) Wait(id string) <-chan WaitResult {
ch := make(chan WaitResult)
uri := fmt.Sprintf("/%s/containers/%s/wait", APIVersion, id)
go func() {
data, err := client.doRequest("POST", uri, nil, nil)
if err != nil {
ch <- WaitResult{ExitCode: -1, Error: err}
return
}
var result struct {
StatusCode int `json:"StatusCode"`
}
err = json.Unmarshal(data, &result)
ch <- WaitResult{ExitCode: result.StatusCode, Error: err}
}()
return ch
}
func (client *DockerClient) MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error) {
v := url.Values{}
if options != nil {
if options.Since != 0 {
v.Add("since", strconv.Itoa(options.Since))
}
if options.Until != 0 {
v.Add("until", strconv.Itoa(options.Until))
}
if options.Filters != nil {
filterMap := make(map[string][]string)
events := []string{}
if options.Filters.Event != "" {
events = append(events, options.Filters.Event)
}
if len(options.Filters.Events) > 0 {
events = append(events, options.Filters.Events...)
}
if len(events) > 0 {
filterMap["event"] = events
}
images := []string{}
if options.Filters.Image != "" {
images = append(images, options.Filters.Image)
}
if len(options.Filters.Images) > 0 {
images = append(images, options.Filters.Images...)
}
if len(images) > 0 {
filterMap["image"] = images
}
containers := []string{}
if options.Filters.Container != "" {
containers = append(containers, options.Filters.Container)
}
if len(options.Filters.Containers) > 0 {
containers = append(containers, options.Filters.Containers...)
}
if len(containers) > 0 {
filterMap["container"] = containers
}
if len(filterMap) > 0 {
filterJSONBytes, err := json.Marshal(filterMap)
if err != nil {
return nil, err
}
v.Add("filters", string(filterJSONBytes))
}
}
}
uri := fmt.Sprintf("%s/%s/events?%s", client.URL.String(), APIVersion, v.Encode())
resp, err := client.HTTPClient.Get(uri)
if err != nil {
return nil, err
}
decode := func(decoder *json.Decoder) decodingResult {
var event Event
if err := decoder.Decode(&event); err != nil {
return decodingResult{err: err}
} else {
return decodingResult{result: event}
}
}
decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan)
eventOrErrorChan := make(chan EventOrError)
go func() {
for decodingResult := range decodingResultChan {
event, _ := decodingResult.result.(Event)
eventOrErrorChan <- EventOrError{
Event: event,
Error: decodingResult.err,
}
}
close(eventOrErrorChan)
}()
return eventOrErrorChan, nil
}
func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args ...interface{}) {
client.eventStopChan = make(chan struct{})
go func() {
eventErrChan, err := client.MonitorEvents(nil, client.eventStopChan)
if err != nil {
if ec != nil {
ec <- err
}
return
}
for e := range eventErrChan {
if e.Error != nil {
if ec != nil {
ec <- e.Error
}
return
}
cb(&e.Event, ec, args...)
}
}()
}
func (client *DockerClient) StopAllMonitorEvents() {
if client.eventStopChan == nil {
return
}
close(client.eventStopChan)
}
func (client *DockerClient) StartMonitorStats(id string, cb StatCallback, ec chan error, args ...interface{}) {
atomic.StoreInt32(&client.monitorStats, 1)
go client.getStats(id, cb, ec, args...)
}
func (client *DockerClient) getStats(id string, cb StatCallback, ec chan error, args ...interface{}) {
uri := fmt.Sprintf("%s/%s/containers/%s/stats", client.URL.String(), APIVersion, id)
resp, err := client.HTTPClient.Get(uri)
if err != nil {
ec <- err
return
}
defer resp.Body.Close()
dec := json.NewDecoder(resp.Body)
for atomic.LoadInt32(&client.monitorStats) > 0 {
var stats *Stats
if err := dec.Decode(&stats); err != nil {
ec <- err
return
}
cb(id, stats, ec, args...)
}
}
func (client *DockerClient) StopAllMonitorStats() {
atomic.StoreInt32(&client.monitorStats, 0)
}
func (client *DockerClient) TagImage(nameOrID string, repo string, tag string, force bool) error {
v := url.Values{}
v.Set("repo", repo)
v.Set("tag", tag)
if force {
v.Set("force", "1")
}
uri := fmt.Sprintf("/%s/images/%s/tag?%s", APIVersion, nameOrID, v.Encode())
if _, err := client.doRequest("POST", uri, nil, nil); err != nil {
return err
}
return nil
}
func (client *DockerClient) Version() (*Version, error) {
uri := fmt.Sprintf("/%s/version", APIVersion)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
version := &Version{}
err = json.Unmarshal(data, version)
if err != nil {
return nil, err
}
return version, nil
}
func (client *DockerClient) PushImage(name string, tag string, auth *AuthConfig) error {
v := url.Values{}
if tag != "" {
v.Set("tag", tag)
}
uri := fmt.Sprintf("/%s/images/%s/push?%s", APIVersion, url.QueryEscape(name), v.Encode())
req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
if auth != nil {
if encodedAuth, err := auth.encode(); err != nil {
return err
} else {
req.Header.Add("X-Registry-Auth", encodedAuth)
}
}
resp, err := client.HTTPClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
var finalObj map[string]interface{}
for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
}
if err != io.EOF {
return err
}
if err, ok := finalObj["error"]; ok {
return fmt.Errorf("%v", err)
}
return nil
}
func (client *DockerClient) PullImage(name string, auth *AuthConfig) error {
v := url.Values{}
v.Set("fromImage", name)
uri := fmt.Sprintf("/%s/images/create?%s", APIVersion, v.Encode())
req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
if auth != nil {
encoded_auth, err := auth.encode()
if err != nil {
return err
}
req.Header.Add("X-Registry-Auth", encoded_auth)
}
resp, err := client.HTTPClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
return ErrNotFound
}
if resp.StatusCode >= 400 {
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("%s", string(data))
}
var finalObj map[string]interface{}
for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
}
if err != io.EOF {
return err
}
if err, ok := finalObj["error"]; ok {
return fmt.Errorf("%v", err)
}
return nil
}
func (client *DockerClient) InspectImage(id string) (*ImageInfo, error) {
uri := fmt.Sprintf("/%s/images/%s/json", APIVersion, id)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
info := &ImageInfo{}
err = json.Unmarshal(data, info)
if err != nil {
return nil, err
}
return info, nil
}
func (client *DockerClient) LoadImage(reader io.Reader) error {
uri := fmt.Sprintf("/%s/images/load", APIVersion)
_, err := client.doStreamRequest("POST", uri, reader, nil)
return err
}
func (client *DockerClient) RemoveContainer(id string, force, volumes bool) error {
argForce := 0
argVolumes := 0
if force == true {
argForce = 1
}
if volumes == true {
argVolumes = 1
}
args := fmt.Sprintf("force=%d&v=%d", argForce, argVolumes)
uri := fmt.Sprintf("/%s/containers/%s?%s", APIVersion, id, args)
_, err := client.doRequest("DELETE", uri, nil, nil)
return err
}
func (client *DockerClient) ListImages(all bool) ([]*Image, error) {
argAll := 0
if all {
argAll = 1
}
uri := fmt.Sprintf("/%s/images/json?all=%d", APIVersion, argAll)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
var images []*Image
if err := json.Unmarshal(data, &images); err != nil {
return nil, err
}
return images, nil
}
func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete, error) {
argForce := 0
if force {
argForce = 1
}
args := fmt.Sprintf("force=%d", argForce)
uri := fmt.Sprintf("/%s/images/%s?%s", APIVersion, name, args)
data, err := client.doRequest("DELETE", uri, nil, nil)
if err != nil {
return nil, err
}
var imageDelete []*ImageDelete
if err := json.Unmarshal(data, &imageDelete); err != nil {
return nil, err
}
return imageDelete, nil
}
func (client *DockerClient) SearchImages(query, registry string, auth *AuthConfig) ([]ImageSearch, error) {
term := query
if registry != "" {
term = registry + "/" + term
}
uri := fmt.Sprintf("/%s/images/search?term=%s", APIVersion, term)
headers := map[string]string{}
if auth != nil {
if encodedAuth, err := auth.encode(); err != nil {
return nil, err
} else {
headers["X-Registry-Auth"] = encodedAuth
}
}
data, err := client.doRequest("GET", uri, nil, headers)
if err != nil {
return nil, err
}
var imageSearches []ImageSearch
if err := json.Unmarshal(data, &imageSearches); err != nil {
return nil, err
}
return imageSearches, nil
}
func (client *DockerClient) PauseContainer(id string) error {
uri := fmt.Sprintf("/%s/containers/%s/pause", APIVersion, id)
_, err := client.doRequest("POST", uri, nil, nil)
if err != nil {
return err
}
return nil
}
func (client *DockerClient) UnpauseContainer(id string) error {
uri := fmt.Sprintf("/%s/containers/%s/unpause", APIVersion, id)
_, err := client.doRequest("POST", uri, nil, nil)
if err != nil {
return err
}
return nil
}
func (client *DockerClient) RenameContainer(oldName string, newName string) error {
uri := fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName)
_, err := client.doRequest("POST", uri, nil, nil)
return err
}
func (client *DockerClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) {
var fromSrc string
v := &url.Values{}
if source == "" {
fromSrc = "-"
} else {
fromSrc = source
}
v.Set("fromSrc", fromSrc)
v.Set("repo", repository)
if tag != "" {
v.Set("tag", tag)
}
var in io.Reader
if fromSrc == "-" {
in = tar
}
return client.doStreamRequest("POST", "/images/create?"+v.Encode(), in, nil)
}
func (client *DockerClient) BuildImage(image *BuildImage) (io.ReadCloser, error) {
v := url.Values{}
if image.DockerfileName != "" {
v.Set("dockerfile", image.DockerfileName)
}
if image.RepoName != "" {
v.Set("t", image.RepoName)
}
if image.RemoteURL != "" {
v.Set("remote", image.RemoteURL)
}
if image.NoCache {
v.Set("nocache", "1")
}
if image.Pull {
v.Set("pull", "1")
}
if image.Remove {
v.Set("rm", "1")
} else {
v.Set("rm", "0")
}
if image.ForceRemove {
v.Set("forcerm", "1")
}
if image.SuppressOutput {
v.Set("q", "1")
}
v.Set("memory", strconv.FormatInt(image.Memory, 10))
v.Set("memswap", strconv.FormatInt(image.MemorySwap, 10))
v.Set("cpushares", strconv.FormatInt(image.CpuShares, 10))
v.Set("cpuperiod", strconv.FormatInt(image.CpuPeriod, 10))
v.Set("cpuquota", strconv.FormatInt(image.CpuQuota, 10))
v.Set("cpusetcpus", image.CpuSetCpus)
v.Set("cpusetmems", image.CpuSetMems)
v.Set("cgroupparent", image.CgroupParent)
if image.BuildArgs != nil {
buildArgsJSON, err := json.Marshal(image.BuildArgs)
if err != nil {
return nil, err
}
v.Set("buildargs", string(buildArgsJSON))
}
headers := make(map[string]string)
if image.Config != nil {
encoded_config, err := image.Config.encode()
if err != nil {
return nil, err
}
headers["X-Registry-Config"] = encoded_config
}
if image.Context != nil {
headers["Content-Type"] = "application/tar"
}
uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode())
return client.doStreamRequest("POST", uri, image.Context, headers)
}
func (client *DockerClient) ListVolumes() ([]*Volume, error) {
uri := fmt.Sprintf("/%s/volumes", APIVersion)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
var volumesList VolumesListResponse
if err := json.Unmarshal(data, &volumesList); err != nil {
return nil, err
}
return volumesList.Volumes, nil
}
func (client *DockerClient) RemoveVolume(name string) error {
uri := fmt.Sprintf("/%s/volumes/%s", APIVersion, name)
_, err := client.doRequest("DELETE", uri, nil, nil)
return err
}
func (client *DockerClient) CreateVolume(request *VolumeCreateRequest) (*Volume, error) {
data, err := json.Marshal(request)
if err != nil {
return nil, err
}
uri := fmt.Sprintf("/%s/volumes/create", APIVersion)
data, err = client.doRequest("POST", uri, data, nil)
if err != nil {
return nil, err
}
volume := &Volume{}
err = json.Unmarshal(data, volume)
return volume, err
}
func (client *DockerClient) ListNetworks(filters string) ([]*NetworkResource, error) {
uri := fmt.Sprintf("/%s/networks", APIVersion)
if filters != "" {
uri += "&filters=" + filters
}
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
ret := []*NetworkResource{}
err = json.Unmarshal(data, &ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (client *DockerClient) InspectNetwork(id string) (*NetworkResource, error) {
uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id)
data, err := client.doRequest("GET", uri, nil, nil)
if err != nil {
return nil, err
}
ret := &NetworkResource{}
err = json.Unmarshal(data, ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (client *DockerClient) CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error) {
data, err := json.Marshal(config)
if err != nil {
return nil, err
}
uri := fmt.Sprintf("/%s/networks/create", APIVersion)
data, err = client.doRequest("POST", uri, data, nil)
if err != nil {
return nil, err
}
ret := &NetworkCreateResponse{}
err = json.Unmarshal(data, ret)
return ret, nil
}
func (client *DockerClient) ConnectNetwork(id, container string) error {
data, err := json.Marshal(NetworkConnect{Container: container})
if err != nil {
return err
}
uri := fmt.Sprintf("/%s/networks/%s/connect", APIVersion, id)
_, err = client.doRequest("POST", uri, data, nil)
return err
}
func (client *DockerClient) DisconnectNetwork(id, container string, force bool) error {
data, err := json.Marshal(NetworkDisconnect{Container: container, Force: force})
if err != nil {
return err
}
uri := fmt.Sprintf("/%s/networks/%s/disconnect", APIVersion, id)
_, err = client.doRequest("POST", uri, data, nil)
return err
}
func (client *DockerClient) RemoveNetwork(id string) error {
uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id)
_, err := client.doRequest("DELETE", uri, nil, nil)
return err
}