1package dockerclient 2 3import ( 4 "bytes" 5 "crypto/tls" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "net/http" 12 "net/url" 13 "strconv" 14 "strings" 15 "sync/atomic" 16 "time" 17) 18 19const ( 20 APIVersion = "v1.15" 21) 22 23var ( 24 ErrImageNotFound = errors.New("Image not found") 25 ErrNotFound = errors.New("Not found") 26 ErrConnectionRefused = errors.New("Cannot connect to the docker engine endpoint") 27 28 defaultTimeout = 30 * time.Second 29) 30 31type DockerClient struct { 32 URL *url.URL 33 HTTPClient *http.Client 34 TLSConfig *tls.Config 35 monitorStats int32 36 eventStopChan chan (struct{}) 37} 38 39type Error struct { 40 StatusCode int 41 Status string 42 msg string 43} 44 45func (e Error) Error() string { 46 return fmt.Sprintf("%s: %s", e.Status, e.msg) 47} 48 49func NewDockerClient(daemonUrl string, tlsConfig *tls.Config) (*DockerClient, error) { 50 return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(defaultTimeout)) 51} 52 53func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration) (*DockerClient, error) { 54 u, err := url.Parse(daemonUrl) 55 if err != nil { 56 return nil, err 57 } 58 if u.Scheme == "" || u.Scheme == "tcp" { 59 if tlsConfig == nil { 60 u.Scheme = "http" 61 } else { 62 u.Scheme = "https" 63 } 64 } 65 httpClient := newHTTPClient(u, tlsConfig, timeout) 66 return &DockerClient{u, httpClient, tlsConfig, 0, nil}, nil 67} 68 69func (client *DockerClient) doRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) { 70 b := bytes.NewBuffer(body) 71 72 reader, err := client.doStreamRequest(method, path, b, headers) 73 if err != nil { 74 return nil, err 75 } 76 77 defer reader.Close() 78 data, err := ioutil.ReadAll(reader) 79 if err != nil { 80 return nil, err 81 } 82 return data, nil 83} 84 85func (client *DockerClient) doStreamRequest(method string, path string, in io.Reader, headers map[string]string) (io.ReadCloser, error) { 86 if (method == "POST" || method == "PUT") && in == nil { 87 in = bytes.NewReader(nil) 88 } 89 req, err := http.NewRequest(method, client.URL.String()+path, in) 90 if err != nil { 91 return nil, err 92 } 93 req.Header.Add("Content-Type", "application/json") 94 if headers != nil { 95 for header, value := range headers { 96 req.Header.Add(header, value) 97 } 98 } 99 resp, err := client.HTTPClient.Do(req) 100 if err != nil { 101 if !strings.Contains(err.Error(), "connection refused") && client.TLSConfig == nil { 102 return nil, fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err) 103 } 104 if strings.Contains(err.Error(), "connection refused") { 105 return nil, ErrConnectionRefused 106 } 107 return nil, err 108 } 109 if resp.StatusCode == 404 { 110 defer resp.Body.Close() 111 data, err := ioutil.ReadAll(resp.Body) 112 if err != nil { 113 return nil, ErrNotFound 114 } 115 if len(data) > 0 { 116 // check if is image not found error 117 if strings.Index(string(data), "No such image") != -1 { 118 return nil, ErrImageNotFound 119 } 120 return nil, errors.New(string(data)) 121 } 122 return nil, ErrNotFound 123 } 124 if resp.StatusCode >= 400 { 125 defer resp.Body.Close() 126 data, err := ioutil.ReadAll(resp.Body) 127 if err != nil { 128 return nil, err 129 } 130 return nil, Error{StatusCode: resp.StatusCode, Status: resp.Status, msg: string(data)} 131 } 132 133 return resp.Body, nil 134} 135 136func (client *DockerClient) Info() (*Info, error) { 137 uri := fmt.Sprintf("/%s/info", APIVersion) 138 data, err := client.doRequest("GET", uri, nil, nil) 139 if err != nil { 140 return nil, err 141 } 142 ret := &Info{} 143 err = json.Unmarshal(data, &ret) 144 if err != nil { 145 return nil, err 146 } 147 return ret, nil 148} 149 150func (client *DockerClient) ListContainers(all bool, size bool, filters string) ([]Container, error) { 151 argAll := 0 152 if all == true { 153 argAll = 1 154 } 155 showSize := 0 156 if size == true { 157 showSize = 1 158 } 159 uri := fmt.Sprintf("/%s/containers/json?all=%d&size=%d", APIVersion, argAll, showSize) 160 161 if filters != "" { 162 uri += "&filters=" + filters 163 } 164 165 data, err := client.doRequest("GET", uri, nil, nil) 166 if err != nil { 167 return nil, err 168 } 169 ret := []Container{} 170 err = json.Unmarshal(data, &ret) 171 if err != nil { 172 return nil, err 173 } 174 return ret, nil 175} 176 177func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) { 178 uri := fmt.Sprintf("/%s/containers/%s/json", APIVersion, id) 179 data, err := client.doRequest("GET", uri, nil, nil) 180 if err != nil { 181 return nil, err 182 } 183 info := &ContainerInfo{} 184 err = json.Unmarshal(data, info) 185 if err != nil { 186 return nil, err 187 } 188 return info, nil 189} 190 191func (client *DockerClient) CreateContainer(config *ContainerConfig, name string, auth *AuthConfig) (string, error) { 192 data, err := json.Marshal(config) 193 if err != nil { 194 return "", err 195 } 196 uri := fmt.Sprintf("/%s/containers/create", APIVersion) 197 if name != "" { 198 v := url.Values{} 199 v.Set("name", name) 200 uri = fmt.Sprintf("%s?%s", uri, v.Encode()) 201 } 202 headers := map[string]string{} 203 if auth != nil { 204 encoded_auth, err := auth.encode() 205 if err != nil { 206 return "", err 207 } 208 headers["X-Registry-Auth"] = encoded_auth 209 } 210 data, err = client.doRequest("POST", uri, data, headers) 211 if err != nil { 212 return "", err 213 } 214 result := &RespContainersCreate{} 215 err = json.Unmarshal(data, result) 216 if err != nil { 217 return "", fmt.Errorf(string(data)) 218 } 219 return result.Id, nil 220} 221 222func (client *DockerClient) ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error) { 223 v := url.Values{} 224 v.Add("follow", strconv.FormatBool(options.Follow)) 225 v.Add("stdout", strconv.FormatBool(options.Stdout)) 226 v.Add("stderr", strconv.FormatBool(options.Stderr)) 227 v.Add("timestamps", strconv.FormatBool(options.Timestamps)) 228 if options.Tail > 0 { 229 v.Add("tail", strconv.FormatInt(options.Tail, 10)) 230 } 231 232 uri := fmt.Sprintf("/%s/containers/%s/logs?%s", APIVersion, id, v.Encode()) 233 req, err := http.NewRequest("GET", client.URL.String()+uri, nil) 234 if err != nil { 235 return nil, err 236 } 237 req.Header.Add("Content-Type", "application/json") 238 resp, err := client.HTTPClient.Do(req) 239 if err != nil { 240 return nil, err 241 } 242 return resp.Body, nil 243} 244 245func (client *DockerClient) ContainerChanges(id string) ([]*ContainerChanges, error) { 246 uri := fmt.Sprintf("/%s/containers/%s/changes", APIVersion, id) 247 data, err := client.doRequest("GET", uri, nil, nil) 248 if err != nil { 249 return nil, err 250 } 251 changes := []*ContainerChanges{} 252 err = json.Unmarshal(data, &changes) 253 if err != nil { 254 return nil, err 255 } 256 return changes, nil 257} 258 259func (client *DockerClient) readJSONStream(stream io.ReadCloser, decode func(*json.Decoder) decodingResult, stopChan <-chan struct{}) <-chan decodingResult { 260 resultChan := make(chan decodingResult) 261 262 go func() { 263 decodeChan := make(chan decodingResult) 264 265 go func() { 266 decoder := json.NewDecoder(stream) 267 for { 268 decodeResult := decode(decoder) 269 decodeChan <- decodeResult 270 if decodeResult.err != nil { 271 close(decodeChan) 272 return 273 } 274 } 275 }() 276 277 defer close(resultChan) 278 279 for { 280 select { 281 case <-stopChan: 282 stream.Close() 283 for range decodeChan { 284 } 285 return 286 case decodeResult := <-decodeChan: 287 resultChan <- decodeResult 288 if decodeResult.err != nil { 289 stream.Close() 290 return 291 } 292 } 293 } 294 295 }() 296 297 return resultChan 298} 299 300func (client *DockerClient) ExecCreate(config *ExecConfig) (string, error) { 301 data, err := json.Marshal(config) 302 if err != nil { 303 return "", err 304 } 305 uri := fmt.Sprintf("/%s/containers/%s/exec", APIVersion, config.Container) 306 resp, err := client.doRequest("POST", uri, data, nil) 307 if err != nil { 308 return "", err 309 } 310 var createExecResp struct { 311 Id string 312 } 313 if err = json.Unmarshal(resp, &createExecResp); err != nil { 314 return "", err 315 } 316 return createExecResp.Id, nil 317} 318 319func (client *DockerClient) ExecStart(id string, config *ExecConfig) error { 320 data, err := json.Marshal(config) 321 if err != nil { 322 return err 323 } 324 325 uri := fmt.Sprintf("/%s/exec/%s/start", APIVersion, id) 326 if _, err := client.doRequest("POST", uri, data, nil); err != nil { 327 return err 328 } 329 330 return nil 331} 332 333func (client *DockerClient) ExecResize(id string, width, height int) error { 334 v := url.Values{} 335 336 w := strconv.Itoa(width) 337 h := strconv.Itoa(height) 338 339 v.Set("w", w) 340 v.Set("h", h) 341 342 uri := fmt.Sprintf("/%s/exec/%s/resize?%s", APIVersion, id, v.Encode()) 343 if _, err := client.doRequest("POST", client.URL.String()+uri, nil, nil); err != nil { 344 return err 345 } 346 347 return nil 348} 349 350func (client *DockerClient) AttachContainer(id string, options *AttachOptions) (io.ReadCloser, error) { 351 v := url.Values{} 352 if options != nil { 353 if options.Logs { 354 v.Set("logs", "1") 355 } 356 if options.Stream { 357 v.Set("stream", "1") 358 } 359 if options.Stdin { 360 v.Set("stdin", "1") 361 } 362 if options.Stdout { 363 v.Set("stdout", "1") 364 } 365 if options.Stderr { 366 v.Set("stderr", "1") 367 } 368 } 369 uri := fmt.Sprintf("/%s/containers/%s/attach?%s", APIVersion, id, v.Encode()) 370 return client.doStreamRequest("POST", uri, nil, nil) 371} 372 373func (client *DockerClient) StartContainer(id string, config *HostConfig) error { 374 data, err := json.Marshal(config) 375 if err != nil { 376 return err 377 } 378 uri := fmt.Sprintf("/%s/containers/%s/start", APIVersion, id) 379 _, err = client.doRequest("POST", uri, data, nil) 380 if err != nil { 381 return err 382 } 383 return nil 384} 385 386func (client *DockerClient) StopContainer(id string, timeout int) error { 387 uri := fmt.Sprintf("/%s/containers/%s/stop?t=%d", APIVersion, id, timeout) 388 _, err := client.doRequest("POST", uri, nil, nil) 389 if err != nil { 390 return err 391 } 392 return nil 393} 394 395func (client *DockerClient) RestartContainer(id string, timeout int) error { 396 uri := fmt.Sprintf("/%s/containers/%s/restart?t=%d", APIVersion, id, timeout) 397 _, err := client.doRequest("POST", uri, nil, nil) 398 if err != nil { 399 return err 400 } 401 return nil 402} 403 404func (client *DockerClient) KillContainer(id, signal string) error { 405 uri := fmt.Sprintf("/%s/containers/%s/kill?signal=%s", APIVersion, id, signal) 406 _, err := client.doRequest("POST", uri, nil, nil) 407 if err != nil { 408 return err 409 } 410 return nil 411} 412 413func (client *DockerClient) Wait(id string) <-chan WaitResult { 414 ch := make(chan WaitResult) 415 uri := fmt.Sprintf("/%s/containers/%s/wait", APIVersion, id) 416 417 go func() { 418 data, err := client.doRequest("POST", uri, nil, nil) 419 if err != nil { 420 ch <- WaitResult{ExitCode: -1, Error: err} 421 return 422 } 423 424 var result struct { 425 StatusCode int `json:"StatusCode"` 426 } 427 err = json.Unmarshal(data, &result) 428 ch <- WaitResult{ExitCode: result.StatusCode, Error: err} 429 }() 430 return ch 431} 432 433func (client *DockerClient) MonitorEvents(options *MonitorEventsOptions, stopChan <-chan struct{}) (<-chan EventOrError, error) { 434 v := url.Values{} 435 if options != nil { 436 if options.Since != 0 { 437 v.Add("since", strconv.Itoa(options.Since)) 438 } 439 if options.Until != 0 { 440 v.Add("until", strconv.Itoa(options.Until)) 441 } 442 if options.Filters != nil { 443 filterMap := make(map[string][]string) 444 if len(options.Filters.Event) > 0 { 445 filterMap["event"] = []string{options.Filters.Event} 446 } 447 if len(options.Filters.Image) > 0 { 448 filterMap["image"] = []string{options.Filters.Image} 449 } 450 if len(options.Filters.Container) > 0 { 451 filterMap["container"] = []string{options.Filters.Container} 452 } 453 if len(filterMap) > 0 { 454 filterJSONBytes, err := json.Marshal(filterMap) 455 if err != nil { 456 return nil, err 457 } 458 v.Add("filters", string(filterJSONBytes)) 459 } 460 } 461 } 462 uri := fmt.Sprintf("%s/%s/events?%s", client.URL.String(), APIVersion, v.Encode()) 463 resp, err := client.HTTPClient.Get(uri) 464 if err != nil { 465 return nil, err 466 } 467 468 decode := func(decoder *json.Decoder) decodingResult { 469 var event Event 470 if err := decoder.Decode(&event); err != nil { 471 return decodingResult{err: err} 472 } else { 473 return decodingResult{result: event} 474 } 475 } 476 decodingResultChan := client.readJSONStream(resp.Body, decode, stopChan) 477 eventOrErrorChan := make(chan EventOrError) 478 go func() { 479 for decodingResult := range decodingResultChan { 480 event, _ := decodingResult.result.(Event) 481 eventOrErrorChan <- EventOrError{ 482 Event: event, 483 Error: decodingResult.err, 484 } 485 } 486 close(eventOrErrorChan) 487 }() 488 return eventOrErrorChan, nil 489} 490 491func (client *DockerClient) StartMonitorEvents(cb Callback, ec chan error, args ...interface{}) { 492 client.eventStopChan = make(chan struct{}) 493 494 go func() { 495 eventErrChan, err := client.MonitorEvents(nil, client.eventStopChan) 496 if err != nil { 497 if ec != nil { 498 ec <- err 499 } 500 return 501 } 502 503 for e := range eventErrChan { 504 if e.Error != nil { 505 if ec != nil { 506 ec <- err 507 } 508 return 509 } 510 cb(&e.Event, ec, args...) 511 } 512 }() 513} 514 515func (client *DockerClient) StopAllMonitorEvents() { 516 if client.eventStopChan == nil { 517 return 518 } 519 close(client.eventStopChan) 520} 521 522func (client *DockerClient) StartMonitorStats(id string, cb StatCallback, ec chan error, args ...interface{}) { 523 atomic.StoreInt32(&client.monitorStats, 1) 524 go client.getStats(id, cb, ec, args...) 525} 526 527func (client *DockerClient) getStats(id string, cb StatCallback, ec chan error, args ...interface{}) { 528 uri := fmt.Sprintf("%s/%s/containers/%s/stats", client.URL.String(), APIVersion, id) 529 resp, err := client.HTTPClient.Get(uri) 530 if err != nil { 531 ec <- err 532 return 533 } 534 defer resp.Body.Close() 535 536 dec := json.NewDecoder(resp.Body) 537 for atomic.LoadInt32(&client.monitorStats) > 0 { 538 var stats *Stats 539 if err := dec.Decode(&stats); err != nil { 540 ec <- err 541 return 542 } 543 cb(id, stats, ec, args...) 544 } 545} 546 547func (client *DockerClient) StopAllMonitorStats() { 548 atomic.StoreInt32(&client.monitorStats, 0) 549} 550 551func (client *DockerClient) TagImage(nameOrID string, repo string, tag string, force bool) error { 552 v := url.Values{} 553 v.Set("repo", repo) 554 v.Set("tag", tag) 555 if force { 556 v.Set("force", "1") 557 } 558 uri := fmt.Sprintf("/%s/images/%s/tag?%s", APIVersion, nameOrID, v.Encode()) 559 if _, err := client.doRequest("POST", uri, nil, nil); err != nil { 560 return err 561 } 562 return nil 563} 564 565func (client *DockerClient) Version() (*Version, error) { 566 uri := fmt.Sprintf("/%s/version", APIVersion) 567 data, err := client.doRequest("GET", uri, nil, nil) 568 if err != nil { 569 return nil, err 570 } 571 version := &Version{} 572 err = json.Unmarshal(data, version) 573 if err != nil { 574 return nil, err 575 } 576 return version, nil 577} 578 579func (client *DockerClient) PushImage(name string, tag string, auth *AuthConfig) error { 580 v := url.Values{} 581 if tag != "" { 582 v.Set("tag", tag) 583 } 584 uri := fmt.Sprintf("/%s/images/%s/push?%s", APIVersion, url.QueryEscape(name), v.Encode()) 585 req, err := http.NewRequest("POST", client.URL.String()+uri, nil) 586 if auth != nil { 587 if encodedAuth, err := auth.encode(); err != nil { 588 return err 589 } else { 590 req.Header.Add("X-Registry-Auth", encodedAuth) 591 } 592 } 593 resp, err := client.HTTPClient.Do(req) 594 if err != nil { 595 return err 596 } 597 defer resp.Body.Close() 598 var finalObj map[string]interface{} 599 for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) { 600 } 601 if err != io.EOF { 602 return err 603 } 604 if err, ok := finalObj["error"]; ok { 605 return fmt.Errorf("%v", err) 606 } 607 return nil 608} 609 610func (client *DockerClient) PullImage(name string, auth *AuthConfig) error { 611 v := url.Values{} 612 v.Set("fromImage", name) 613 uri := fmt.Sprintf("/%s/images/create?%s", APIVersion, v.Encode()) 614 req, err := http.NewRequest("POST", client.URL.String()+uri, nil) 615 if auth != nil { 616 encoded_auth, err := auth.encode() 617 if err != nil { 618 return err 619 } 620 req.Header.Add("X-Registry-Auth", encoded_auth) 621 } 622 resp, err := client.HTTPClient.Do(req) 623 if err != nil { 624 return err 625 } 626 627 defer resp.Body.Close() 628 if resp.StatusCode == 404 { 629 return ErrNotFound 630 } 631 if resp.StatusCode >= 400 { 632 data, err := ioutil.ReadAll(resp.Body) 633 if err != nil { 634 return err 635 } 636 return fmt.Errorf("%s", string(data)) 637 } 638 639 var finalObj map[string]interface{} 640 for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) { 641 } 642 if err != io.EOF { 643 return err 644 } 645 if err, ok := finalObj["error"]; ok { 646 return fmt.Errorf("%v", err) 647 } 648 return nil 649} 650 651func (client *DockerClient) InspectImage(id string) (*ImageInfo, error) { 652 uri := fmt.Sprintf("/%s/images/%s/json", APIVersion, id) 653 data, err := client.doRequest("GET", uri, nil, nil) 654 if err != nil { 655 return nil, err 656 } 657 info := &ImageInfo{} 658 err = json.Unmarshal(data, info) 659 if err != nil { 660 return nil, err 661 } 662 return info, nil 663} 664 665func (client *DockerClient) LoadImage(reader io.Reader) error { 666 uri := fmt.Sprintf("/%s/images/load", APIVersion) 667 _, err := client.doStreamRequest("POST", uri, reader, nil) 668 return err 669} 670 671func (client *DockerClient) RemoveContainer(id string, force, volumes bool) error { 672 argForce := 0 673 argVolumes := 0 674 if force == true { 675 argForce = 1 676 } 677 if volumes == true { 678 argVolumes = 1 679 } 680 args := fmt.Sprintf("force=%d&v=%d", argForce, argVolumes) 681 uri := fmt.Sprintf("/%s/containers/%s?%s", APIVersion, id, args) 682 _, err := client.doRequest("DELETE", uri, nil, nil) 683 return err 684} 685 686func (client *DockerClient) ListImages(all bool) ([]*Image, error) { 687 argAll := 0 688 if all { 689 argAll = 1 690 } 691 uri := fmt.Sprintf("/%s/images/json?all=%d", APIVersion, argAll) 692 data, err := client.doRequest("GET", uri, nil, nil) 693 if err != nil { 694 return nil, err 695 } 696 var images []*Image 697 if err := json.Unmarshal(data, &images); err != nil { 698 return nil, err 699 } 700 return images, nil 701} 702 703func (client *DockerClient) RemoveImage(name string, force bool) ([]*ImageDelete, error) { 704 argForce := 0 705 if force { 706 argForce = 1 707 } 708 709 args := fmt.Sprintf("force=%d", argForce) 710 uri := fmt.Sprintf("/%s/images/%s?%s", APIVersion, name, args) 711 data, err := client.doRequest("DELETE", uri, nil, nil) 712 if err != nil { 713 return nil, err 714 } 715 var imageDelete []*ImageDelete 716 if err := json.Unmarshal(data, &imageDelete); err != nil { 717 return nil, err 718 } 719 return imageDelete, nil 720} 721 722func (client *DockerClient) PauseContainer(id string) error { 723 uri := fmt.Sprintf("/%s/containers/%s/pause", APIVersion, id) 724 _, err := client.doRequest("POST", uri, nil, nil) 725 if err != nil { 726 return err 727 } 728 return nil 729} 730func (client *DockerClient) UnpauseContainer(id string) error { 731 uri := fmt.Sprintf("/%s/containers/%s/unpause", APIVersion, id) 732 _, err := client.doRequest("POST", uri, nil, nil) 733 if err != nil { 734 return err 735 } 736 return nil 737} 738 739func (client *DockerClient) RenameContainer(oldName string, newName string) error { 740 uri := fmt.Sprintf("/containers/%s/rename?name=%s", oldName, newName) 741 _, err := client.doRequest("POST", uri, nil, nil) 742 return err 743} 744 745func (client *DockerClient) ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error) { 746 var fromSrc string 747 v := &url.Values{} 748 if source == "" { 749 fromSrc = "-" 750 } else { 751 fromSrc = source 752 } 753 754 v.Set("fromSrc", fromSrc) 755 v.Set("repo", repository) 756 if tag != "" { 757 v.Set("tag", tag) 758 } 759 760 var in io.Reader 761 if fromSrc == "-" { 762 in = tar 763 } 764 return client.doStreamRequest("POST", "/images/create?"+v.Encode(), in, nil) 765} 766 767func (client *DockerClient) BuildImage(image *BuildImage) (io.ReadCloser, error) { 768 v := url.Values{} 769 770 if image.DockerfileName != "" { 771 v.Set("dockerfile", image.DockerfileName) 772 } 773 if image.RepoName != "" { 774 v.Set("t", image.RepoName) 775 } 776 if image.RemoteURL != "" { 777 v.Set("remote", image.RemoteURL) 778 } 779 if image.NoCache { 780 v.Set("nocache", "1") 781 } 782 if image.Pull { 783 v.Set("pull", "1") 784 } 785 if image.Remove { 786 v.Set("rm", "1") 787 } else { 788 v.Set("rm", "0") 789 } 790 if image.ForceRemove { 791 v.Set("forcerm", "1") 792 } 793 if image.SuppressOutput { 794 v.Set("q", "1") 795 } 796 797 v.Set("memory", strconv.FormatInt(image.Memory, 10)) 798 v.Set("memswap", strconv.FormatInt(image.MemorySwap, 10)) 799 v.Set("cpushares", strconv.FormatInt(image.CpuShares, 10)) 800 v.Set("cpuperiod", strconv.FormatInt(image.CpuPeriod, 10)) 801 v.Set("cpuquota", strconv.FormatInt(image.CpuQuota, 10)) 802 v.Set("cpusetcpus", image.CpuSetCpus) 803 v.Set("cpusetmems", image.CpuSetMems) 804 v.Set("cgroupparent", image.CgroupParent) 805 if image.BuildArgs != nil { 806 buildArgsJSON, err := json.Marshal(image.BuildArgs) 807 if err != nil { 808 return nil, err 809 } 810 v.Set("buildargs", string(buildArgsJSON)) 811 } 812 813 headers := make(map[string]string) 814 if image.Config != nil { 815 encoded_config, err := image.Config.encode() 816 if err != nil { 817 return nil, err 818 } 819 headers["X-Registry-Config"] = encoded_config 820 } 821 if image.Context != nil { 822 headers["Content-Type"] = "application/tar" 823 } 824 825 uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode()) 826 return client.doStreamRequest("POST", uri, image.Context, headers) 827} 828 829func (client *DockerClient) ListVolumes() ([]*Volume, error) { 830 uri := fmt.Sprintf("/%s/volumes", APIVersion) 831 data, err := client.doRequest("GET", uri, nil, nil) 832 if err != nil { 833 return nil, err 834 } 835 var volumesList VolumesListResponse 836 if err := json.Unmarshal(data, &volumesList); err != nil { 837 return nil, err 838 } 839 return volumesList.Volumes, nil 840} 841 842func (client *DockerClient) RemoveVolume(name string) error { 843 uri := fmt.Sprintf("/%s/volumes/%s", APIVersion, name) 844 _, err := client.doRequest("DELETE", uri, nil, nil) 845 return err 846} 847 848func (client *DockerClient) CreateVolume(request *VolumeCreateRequest) (*Volume, error) { 849 data, err := json.Marshal(request) 850 if err != nil { 851 return nil, err 852 } 853 uri := fmt.Sprintf("/%s/volumes/create", APIVersion) 854 data, err = client.doRequest("POST", uri, data, nil) 855 if err != nil { 856 return nil, err 857 } 858 volume := &Volume{} 859 err = json.Unmarshal(data, volume) 860 return volume, err 861} 862 863func (client *DockerClient) ListNetworks(filters string) ([]*NetworkResource, error) { 864 uri := fmt.Sprintf("/%s/networks", APIVersion) 865 866 if filters != "" { 867 uri += "&filters=" + filters 868 } 869 870 data, err := client.doRequest("GET", uri, nil, nil) 871 if err != nil { 872 return nil, err 873 } 874 ret := []*NetworkResource{} 875 err = json.Unmarshal(data, &ret) 876 if err != nil { 877 return nil, err 878 } 879 return ret, nil 880} 881 882func (client *DockerClient) InspectNetwork(id string) (*NetworkResource, error) { 883 uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id) 884 885 data, err := client.doRequest("GET", uri, nil, nil) 886 if err != nil { 887 return nil, err 888 } 889 ret := &NetworkResource{} 890 err = json.Unmarshal(data, ret) 891 if err != nil { 892 return nil, err 893 } 894 895 return ret, nil 896} 897 898func (client *DockerClient) CreateNetwork(config *NetworkCreate) (*NetworkCreateResponse, error) { 899 data, err := json.Marshal(config) 900 if err != nil { 901 return nil, err 902 } 903 uri := fmt.Sprintf("/%s/networks/create", APIVersion) 904 data, err = client.doRequest("POST", uri, data, nil) 905 if err != nil { 906 return nil, err 907 } 908 ret := &NetworkCreateResponse{} 909 err = json.Unmarshal(data, ret) 910 return ret, nil 911} 912 913func (client *DockerClient) ConnectNetwork(id, container string) error { 914 data, err := json.Marshal(NetworkConnect{Container: container}) 915 if err != nil { 916 return err 917 } 918 uri := fmt.Sprintf("/%s/networks/%s/connect", APIVersion, id) 919 _, err = client.doRequest("POST", uri, data, nil) 920 return err 921} 922 923func (client *DockerClient) DisconnectNetwork(id, container string) error { 924 data, err := json.Marshal(NetworkDisconnect{Container: container}) 925 if err != nil { 926 return err 927 } 928 uri := fmt.Sprintf("/%s/networks/%s/disconnect", APIVersion, id) 929 _, err = client.doRequest("POST", uri, data, nil) 930 return err 931} 932 933func (client *DockerClient) RemoveNetwork(id string) error { 934 uri := fmt.Sprintf("/%s/networks/%s", APIVersion, id) 935 _, err := client.doRequest("DELETE", uri, nil, nil) 936 return err 937} 938