├── api ├── common_unix.go ├── types │ ├── swarm │ │ ├── runtime │ │ │ ├── gen.go │ │ │ └── plugin.proto │ │ ├── runtime.go │ │ ├── config.go │ │ ├── secret.go │ │ └── common.go │ ├── plugins │ │ └── logdriver │ │ │ ├── gen.go │ │ │ └── entry.proto │ ├── time │ │ ├── duration_convert.go │ │ └── duration_convert_test.go │ ├── error_response.go │ ├── id_response.go │ ├── service_update_response.go │ ├── graph_driver_data.go │ ├── image_delete_response_item.go │ ├── blkiodev │ │ └── blkio.go │ ├── plugin_interface_type.go │ ├── container │ │ ├── container_update.go │ │ ├── container_wait.go │ │ ├── container_changes.go │ │ ├── container_create.go │ │ ├── container_top.go │ │ ├── waitcondition.go │ │ ├── hostconfig_unix.go │ │ └── hostconfig_windows.go │ ├── port.go │ ├── plugin_env.go │ ├── plugin_device.go │ ├── filters │ │ └── example_test.go │ ├── registry │ │ └── authenticate.go │ ├── volume │ │ ├── volumes_list.go │ │ └── volumes_create.go │ ├── auth.go │ ├── versions │ │ ├── compare_test.go │ │ ├── v1p19 │ │ │ └── types.go │ │ ├── README.md │ │ ├── v1p20 │ │ │ └── types.go │ │ └── compare.go │ ├── plugin_mount.go │ ├── strslice │ │ └── strslice.go │ ├── image │ │ └── image_history.go │ ├── image_summary.go │ ├── plugin_responses.go │ └── events │ │ └── events.go ├── common.go ├── common_windows.go └── swagger-gen.yaml ├── client_windows.go ├── client_unix.go ├── interface_stable.go ├── tlsconfig_clone.go ├── plugin_set.go ├── swarm_join.go ├── service_remove.go ├── container_unpause.go ├── container_pause.go ├── swarm_unlock.go ├── network_remove.go ├── transport.go ├── swarm_leave.go ├── scripts ├── vanity-url │ └── go-docker.html ├── files │ └── doc.go └── update.sh ├── config_remove.go ├── secret_remove.go ├── checkpoint_create.go ├── container_rename.go ├── plugin_push.go ├── container_kill.go ├── session.go ├── plugin_disable.go ├── plugin_enable.go ├── distribution_inspect_test.go ├── network_disconnect.go ├── node_update.go ├── node_remove.go ├── plugin_remove.go ├── swarm_inspect.go ├── swarm_init.go ├── version.go ├── container_export.go ├── image_save.go ├── network_connect.go ├── volume_remove.go ├── swarm_get_unlock_key.go ├── volume_create.go ├── checkpoint_delete.go ├── config_update.go ├── secret_update.go ├── interface_experimental.go ├── image_history.go ├── info.go ├── disk_usage.go ├── container_stop.go ├── plugin_create.go ├── container_update.go ├── Gopkg.toml ├── container_start.go ├── container_diff.go ├── container_restart.go ├── config_create.go ├── container_remove.go ├── secret_create.go ├── plugin_inspect.go ├── network_create.go ├── swarm_update.go ├── container_stats.go ├── container_top.go ├── node_inspect.go ├── image_remove.go ├── task_inspect.go ├── checkpoint_list.go ├── task_list.go ├── node_list.go ├── image_inspect.go ├── utils.go ├── image_load.go ├── plugin_list.go ├── service_list.go ├── login.go ├── volume_list.go ├── ping.go ├── config_inspect.go ├── secret_inspect.go ├── network_list.go ├── config_list.go ├── image_prune.go ├── secret_list.go ├── volume_prune.go ├── container_prune.go ├── network_prune.go ├── doc.go ├── container_resize.go ├── service_inspect.go ├── image_import.go ├── image_create.go ├── distribution_inspect.go ├── image_tag.go ├── container_pause_test.go ├── container_unpause_test.go ├── task_logs.go ├── service_logs.go ├── network_remove_test.go ├── plugin_set_test.go ├── volume_remove_test.go ├── container_list.go ├── image_list.go ├── plugin_upgrade.go ├── swarm_join_test.go ├── container_kill_test.go ├── container_rename_test.go ├── plugin_enable_test.go ├── node_update_test.go ├── plugin_remove_test.go ├── tlsconfig_clone_go17.go ├── plugin_disable_test.go ├── swarm_update_test.go ├── disk_usage_test.go ├── container_stop_test.go ├── container_export_test.go ├── swarm_unlock_test.go ├── volume_inspect.go ├── container_restart_test.go ├── swarm_init_test.go ├── plugin_push_test.go ├── task_inspect_test.go ├── swarm_inspect_test.go ├── plugin_inspect_test.go ├── checkpoint_delete_test.go ├── client_mock_test.go ├── container_inspect.go ├── network_inspect.go ├── container_update_test.go ├── container_diff_test.go ├── service_remove_test.go ├── container_commit.go ├── image_history_test.go ├── image_search.go ├── config_remove_test.go ├── secret_remove_test.go ├── image_save_test.go ├── swarm_leave_test.go ├── image_push.go ├── node_inspect_test.go ├── config_update_test.go ├── secret_update_test.go ├── network_disconnect_test.go ├── container_create.go ├── container_start_test.go ├── node_remove_test.go ├── container_attach.go ├── container_stats_test.go ├── README.md ├── checkpoint_list_test.go ├── service_inspect_test.go ├── container_logs.go ├── config_create_test.go └── secret_create_test.go /api/common_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package api 4 | 5 | // MinVersion represents Minimum REST API version supported 6 | const MinVersion string = "1.12" 7 | -------------------------------------------------------------------------------- /api/types/swarm/runtime/gen.go: -------------------------------------------------------------------------------- 1 | //go:generate protoc -I . --gogofast_out=import_path=docker.io/go-docker/api/types/swarm/runtime:. plugin.proto 2 | 3 | package runtime 4 | -------------------------------------------------------------------------------- /api/types/plugins/logdriver/gen.go: -------------------------------------------------------------------------------- 1 | //go:generate protoc --gogofast_out=import_path=docker.io/go-docker/api/types/plugins/logdriver:. entry.proto 2 | 3 | package logdriver 4 | -------------------------------------------------------------------------------- /api/types/plugins/logdriver/entry.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message LogEntry { 4 | string source = 1; 5 | int64 time_nano = 2; 6 | bytes line = 3; 7 | bool partial = 4; 8 | } 9 | -------------------------------------------------------------------------------- /client_windows.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | // DefaultDockerHost defines os specific default if DOCKER_HOST is unset 4 | const DefaultDockerHost = "npipe:////./pipe/docker_engine" 5 | -------------------------------------------------------------------------------- /client_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd solaris openbsd darwin 2 | 3 | package docker // import "docker.io/go-docker" 4 | 5 | // DefaultDockerHost defines os specific default if DOCKER_HOST is unset 6 | const DefaultDockerHost = "unix:///var/run/docker.sock" 7 | -------------------------------------------------------------------------------- /interface_stable.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | // APIClient is an interface that clients that talk with a docker server must implement. 4 | type APIClient interface { 5 | CommonAPIClient 6 | apiClientExperimental 7 | } 8 | 9 | // Ensure that Client always implements APIClient. 10 | var _ APIClient = &Client{} 11 | -------------------------------------------------------------------------------- /api/common.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // Common constants for daemon and client. 4 | const ( 5 | // DefaultVersion of Current REST API 6 | DefaultVersion string = "1.33" 7 | 8 | // NoBaseImageSpecifier is the symbol used by the FROM 9 | // command to specify that no base image is to be used. 10 | NoBaseImageSpecifier string = "scratch" 11 | ) 12 | -------------------------------------------------------------------------------- /tlsconfig_clone.go: -------------------------------------------------------------------------------- 1 | // +build go1.8 2 | 3 | package docker // import "docker.io/go-docker" 4 | 5 | import "crypto/tls" 6 | 7 | // tlsConfigClone returns a clone of tls.Config. This function is provided for 8 | // compatibility for go1.7 that doesn't include this method in stdlib. 9 | func tlsConfigClone(c *tls.Config) *tls.Config { 10 | return c.Clone() 11 | } 12 | -------------------------------------------------------------------------------- /api/types/time/duration_convert.go: -------------------------------------------------------------------------------- 1 | package time 2 | 3 | import ( 4 | "strconv" 5 | "time" 6 | ) 7 | 8 | // DurationToSecondsString converts the specified duration to the number 9 | // seconds it represents, formatted as a string. 10 | func DurationToSecondsString(duration time.Duration) string { 11 | return strconv.FormatFloat(duration.Seconds(), 'f', 0, 64) 12 | } 13 | -------------------------------------------------------------------------------- /plugin_set.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "golang.org/x/net/context" 5 | ) 6 | 7 | // PluginSet modifies settings for an existing plugin 8 | func (cli *Client) PluginSet(ctx context.Context, name string, args []string) error { 9 | resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, args, nil) 10 | ensureReaderClosed(resp) 11 | return err 12 | } 13 | -------------------------------------------------------------------------------- /api/types/error_response.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // ErrorResponse Represents an error. 7 | // swagger:model ErrorResponse 8 | type ErrorResponse struct { 9 | 10 | // The error message. 11 | // Required: true 12 | Message string `json:"message"` 13 | } 14 | -------------------------------------------------------------------------------- /swarm_join.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "docker.io/go-docker/api/types/swarm" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | // SwarmJoin joins the swarm. 9 | func (cli *Client) SwarmJoin(ctx context.Context, req swarm.JoinRequest) error { 10 | resp, err := cli.post(ctx, "/swarm/join", nil, req, nil) 11 | ensureReaderClosed(resp) 12 | return err 13 | } 14 | -------------------------------------------------------------------------------- /service_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import "golang.org/x/net/context" 4 | 5 | // ServiceRemove kills and removes a service. 6 | func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error { 7 | resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil) 8 | ensureReaderClosed(resp) 9 | return wrapResponseError(err, resp, "service", serviceID) 10 | } 11 | -------------------------------------------------------------------------------- /api/common_windows.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // MinVersion represents Minimum REST API version supported 4 | // Technically the first daemon API version released on Windows is v1.25 in 5 | // engine version 1.13. However, some clients are explicitly using downlevel 6 | // APIs (e.g. docker-compose v2.1 file format) and that is just too restrictive. 7 | // Hence also allowing 1.24 on Windows. 8 | const MinVersion string = "1.24" 9 | -------------------------------------------------------------------------------- /container_unpause.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import "golang.org/x/net/context" 4 | 5 | // ContainerUnpause resumes the process execution within a container 6 | func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error { 7 | resp, err := cli.post(ctx, "/containers/"+containerID+"/unpause", nil, nil, nil) 8 | ensureReaderClosed(resp) 9 | return err 10 | } 11 | -------------------------------------------------------------------------------- /api/types/id_response.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // IDResponse Response to an API call that returns just an Id 7 | // swagger:model IdResponse 8 | type IDResponse struct { 9 | 10 | // The id of the newly created object. 11 | // Required: true 12 | ID string `json:"Id"` 13 | } 14 | -------------------------------------------------------------------------------- /api/types/service_update_response.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // ServiceUpdateResponse service update response 7 | // swagger:model ServiceUpdateResponse 8 | type ServiceUpdateResponse struct { 9 | 10 | // Optional warning messages 11 | Warnings []string `json:"Warnings"` 12 | } 13 | -------------------------------------------------------------------------------- /container_pause.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import "golang.org/x/net/context" 4 | 5 | // ContainerPause pauses the main process of a given container without terminating it. 6 | func (cli *Client) ContainerPause(ctx context.Context, containerID string) error { 7 | resp, err := cli.post(ctx, "/containers/"+containerID+"/pause", nil, nil, nil) 8 | ensureReaderClosed(resp) 9 | return err 10 | } 11 | -------------------------------------------------------------------------------- /swarm_unlock.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "docker.io/go-docker/api/types/swarm" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | // SwarmUnlock unlocks locked swarm. 9 | func (cli *Client) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error { 10 | serverResp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil) 11 | ensureReaderClosed(serverResp) 12 | return err 13 | } 14 | -------------------------------------------------------------------------------- /api/swagger-gen.yaml: -------------------------------------------------------------------------------- 1 | 2 | layout: 3 | models: 4 | - name: definition 5 | source: asset:model 6 | target: "{{ joinFilePath .Target .ModelPackage }}" 7 | file_name: "{{ (snakize (pascalize .Name)) }}.go" 8 | operations: 9 | - name: handler 10 | source: asset:serverOperation 11 | target: "{{ joinFilePath .Target .APIPackage .Package }}" 12 | file_name: "{{ (snakize (pascalize .Name)) }}.go" 13 | -------------------------------------------------------------------------------- /network_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import "golang.org/x/net/context" 4 | 5 | // NetworkRemove removes an existent network from the docker host. 6 | func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { 7 | resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) 8 | ensureReaderClosed(resp) 9 | return wrapResponseError(err, resp, "network", networkID) 10 | } 11 | -------------------------------------------------------------------------------- /transport.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "crypto/tls" 5 | "net/http" 6 | ) 7 | 8 | // resolveTLSConfig attempts to resolve the TLS configuration from the 9 | // RoundTripper. 10 | func resolveTLSConfig(transport http.RoundTripper) *tls.Config { 11 | switch tr := transport.(type) { 12 | case *http.Transport: 13 | return tr.TLSClientConfig 14 | default: 15 | return nil 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /swarm_leave.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // SwarmLeave leaves the swarm. 10 | func (cli *Client) SwarmLeave(ctx context.Context, force bool) error { 11 | query := url.Values{} 12 | if force { 13 | query.Set("force", "1") 14 | } 15 | resp, err := cli.post(ctx, "/swarm/leave", query, nil, nil) 16 | ensureReaderClosed(resp) 17 | return err 18 | } 19 | -------------------------------------------------------------------------------- /scripts/vanity-url/go-docker.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /config_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import "golang.org/x/net/context" 4 | 5 | // ConfigRemove removes a Config. 6 | func (cli *Client) ConfigRemove(ctx context.Context, id string) error { 7 | if err := cli.NewVersionError("1.30", "config remove"); err != nil { 8 | return err 9 | } 10 | resp, err := cli.delete(ctx, "/configs/"+id, nil, nil) 11 | ensureReaderClosed(resp) 12 | return wrapResponseError(err, resp, "config", id) 13 | } 14 | -------------------------------------------------------------------------------- /secret_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import "golang.org/x/net/context" 4 | 5 | // SecretRemove removes a Secret. 6 | func (cli *Client) SecretRemove(ctx context.Context, id string) error { 7 | if err := cli.NewVersionError("1.25", "secret remove"); err != nil { 8 | return err 9 | } 10 | resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil) 11 | ensureReaderClosed(resp) 12 | return wrapResponseError(err, resp, "secret", id) 13 | } 14 | -------------------------------------------------------------------------------- /api/types/graph_driver_data.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // GraphDriverData Information about a container's graph driver. 7 | // swagger:model GraphDriverData 8 | type GraphDriverData struct { 9 | 10 | // data 11 | // Required: true 12 | Data map[string]string `json:"Data"` 13 | 14 | // name 15 | // Required: true 16 | Name string `json:"Name"` 17 | } 18 | -------------------------------------------------------------------------------- /checkpoint_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "docker.io/go-docker/api/types" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | // CheckpointCreate creates a checkpoint from the given container with the given name 9 | func (cli *Client) CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error { 10 | resp, err := cli.post(ctx, "/containers/"+container+"/checkpoints", nil, options, nil) 11 | ensureReaderClosed(resp) 12 | return err 13 | } 14 | -------------------------------------------------------------------------------- /container_rename.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // ContainerRename changes the name of a given container. 10 | func (cli *Client) ContainerRename(ctx context.Context, containerID, newContainerName string) error { 11 | query := url.Values{} 12 | query.Set("name", newContainerName) 13 | resp, err := cli.post(ctx, "/containers/"+containerID+"/rename", query, nil, nil) 14 | ensureReaderClosed(resp) 15 | return err 16 | } 17 | -------------------------------------------------------------------------------- /plugin_push.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // PluginPush pushes a plugin to a registry 10 | func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) { 11 | headers := map[string][]string{"X-Registry-Auth": {registryAuth}} 12 | resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, headers) 13 | if err != nil { 14 | return nil, err 15 | } 16 | return resp.body, nil 17 | } 18 | -------------------------------------------------------------------------------- /container_kill.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // ContainerKill terminates the container process but does not remove the container from the docker host. 10 | func (cli *Client) ContainerKill(ctx context.Context, containerID, signal string) error { 11 | query := url.Values{} 12 | query.Set("signal", signal) 13 | 14 | resp, err := cli.post(ctx, "/containers/"+containerID+"/kill", query, nil, nil) 15 | ensureReaderClosed(resp) 16 | return err 17 | } 18 | -------------------------------------------------------------------------------- /session.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // DialSession returns a connection that can be used communication with daemon 11 | func (cli *Client) DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) { 12 | req, err := http.NewRequest("POST", "/session", nil) 13 | if err != nil { 14 | return nil, err 15 | } 16 | req = cli.addHeaders(req, meta) 17 | 18 | return cli.setupHijackConn(req, proto) 19 | } 20 | -------------------------------------------------------------------------------- /plugin_disable.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // PluginDisable disables a plugin 11 | func (cli *Client) PluginDisable(ctx context.Context, name string, options types.PluginDisableOptions) error { 12 | query := url.Values{} 13 | if options.Force { 14 | query.Set("force", "1") 15 | } 16 | resp, err := cli.post(ctx, "/plugins/"+name+"/disable", query, nil, nil) 17 | ensureReaderClosed(resp) 18 | return err 19 | } 20 | -------------------------------------------------------------------------------- /api/types/image_delete_response_item.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // ImageDeleteResponseItem image delete response item 7 | // swagger:model ImageDeleteResponseItem 8 | type ImageDeleteResponseItem struct { 9 | 10 | // The image ID of an image that was deleted 11 | Deleted string `json:"Deleted,omitempty"` 12 | 13 | // The image ID of an image that was untagged 14 | Untagged string `json:"Untagged,omitempty"` 15 | } 16 | -------------------------------------------------------------------------------- /api/types/swarm/runtime/plugin.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | // PluginSpec defines the base payload which clients can specify for creating 4 | // a service with the plugin runtime. 5 | message PluginSpec { 6 | string name = 1; 7 | string remote = 2; 8 | repeated PluginPrivilege privileges = 3; 9 | bool disabled = 4; 10 | } 11 | 12 | // PluginPrivilege describes a permission the user has to accept 13 | // upon installing a plugin. 14 | message PluginPrivilege { 15 | string name = 1; 16 | string description = 2; 17 | repeated string value = 3; 18 | } 19 | -------------------------------------------------------------------------------- /plugin_enable.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | 7 | "docker.io/go-docker/api/types" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // PluginEnable enables a plugin 12 | func (cli *Client) PluginEnable(ctx context.Context, name string, options types.PluginEnableOptions) error { 13 | query := url.Values{} 14 | query.Set("timeout", strconv.Itoa(options.Timeout)) 15 | 16 | resp, err := cli.post(ctx, "/plugins/"+name+"/enable", query, nil, nil) 17 | ensureReaderClosed(resp) 18 | return err 19 | } 20 | -------------------------------------------------------------------------------- /distribution_inspect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | func TestDistributionInspectUnsupported(t *testing.T) { 12 | client := &Client{ 13 | version: "1.29", 14 | client: &http.Client{}, 15 | } 16 | _, err := client.DistributionInspect(context.Background(), "foobar:1.0", "") 17 | assert.EqualError(t, err, `"distribution inspect" requires API version 1.30, but the Docker daemon API version is 1.29`) 18 | } 19 | -------------------------------------------------------------------------------- /network_disconnect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "docker.io/go-docker/api/types" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | // NetworkDisconnect disconnects a container from an existent network in the docker host. 9 | func (cli *Client) NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error { 10 | nd := types.NetworkDisconnect{Container: containerID, Force: force} 11 | resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, nd, nil) 12 | ensureReaderClosed(resp) 13 | return err 14 | } 15 | -------------------------------------------------------------------------------- /node_update.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | 7 | "docker.io/go-docker/api/types/swarm" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // NodeUpdate updates a Node. 12 | func (cli *Client) NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error { 13 | query := url.Values{} 14 | query.Set("version", strconv.FormatUint(version.Index, 10)) 15 | resp, err := cli.post(ctx, "/nodes/"+nodeID+"/update", query, node, nil) 16 | ensureReaderClosed(resp) 17 | return err 18 | } 19 | -------------------------------------------------------------------------------- /api/types/blkiodev/blkio.go: -------------------------------------------------------------------------------- 1 | package blkiodev 2 | 3 | import "fmt" 4 | 5 | // WeightDevice is a structure that holds device:weight pair 6 | type WeightDevice struct { 7 | Path string 8 | Weight uint16 9 | } 10 | 11 | func (w *WeightDevice) String() string { 12 | return fmt.Sprintf("%s:%d", w.Path, w.Weight) 13 | } 14 | 15 | // ThrottleDevice is a structure that holds device:rate_per_second pair 16 | type ThrottleDevice struct { 17 | Path string 18 | Rate uint64 19 | } 20 | 21 | func (t *ThrottleDevice) String() string { 22 | return fmt.Sprintf("%s:%d", t.Path, t.Rate) 23 | } 24 | -------------------------------------------------------------------------------- /api/types/plugin_interface_type.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // PluginInterfaceType plugin interface type 7 | // swagger:model PluginInterfaceType 8 | type PluginInterfaceType struct { 9 | 10 | // capability 11 | // Required: true 12 | Capability string `json:"Capability"` 13 | 14 | // prefix 15 | // Required: true 16 | Prefix string `json:"Prefix"` 17 | 18 | // version 19 | // Required: true 20 | Version string `json:"Version"` 21 | } 22 | -------------------------------------------------------------------------------- /node_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // NodeRemove removes a Node. 12 | func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error { 13 | query := url.Values{} 14 | if options.Force { 15 | query.Set("force", "1") 16 | } 17 | 18 | resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil) 19 | ensureReaderClosed(resp) 20 | return wrapResponseError(err, resp, "node", nodeID) 21 | } 22 | -------------------------------------------------------------------------------- /plugin_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // PluginRemove removes a plugin 11 | func (cli *Client) PluginRemove(ctx context.Context, name string, options types.PluginRemoveOptions) error { 12 | query := url.Values{} 13 | if options.Force { 14 | query.Set("force", "1") 15 | } 16 | 17 | resp, err := cli.delete(ctx, "/plugins/"+name, query, nil) 18 | ensureReaderClosed(resp) 19 | return wrapResponseError(err, resp, "plugin", name) 20 | } 21 | -------------------------------------------------------------------------------- /swarm_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types/swarm" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // SwarmInspect inspects the swarm. 11 | func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) { 12 | serverResp, err := cli.get(ctx, "/swarm", nil, nil) 13 | if err != nil { 14 | return swarm.Swarm{}, err 15 | } 16 | 17 | var response swarm.Swarm 18 | err = json.NewDecoder(serverResp.body).Decode(&response) 19 | ensureReaderClosed(serverResp) 20 | return response, err 21 | } 22 | -------------------------------------------------------------------------------- /api/types/container/container_update.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // ContainerUpdateOKBody container update o k body 11 | // swagger:model ContainerUpdateOKBody 12 | type ContainerUpdateOKBody struct { 13 | 14 | // warnings 15 | // Required: true 16 | Warnings []string `json:"Warnings"` 17 | } 18 | -------------------------------------------------------------------------------- /api/types/port.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // Port An open port on a container 7 | // swagger:model Port 8 | type Port struct { 9 | 10 | // IP 11 | IP string `json:"IP,omitempty"` 12 | 13 | // Port on the container 14 | // Required: true 15 | PrivatePort uint16 `json:"PrivatePort"` 16 | 17 | // Port exposed on the host 18 | PublicPort uint16 `json:"PublicPort,omitempty"` 19 | 20 | // type 21 | // Required: true 22 | Type string `json:"Type"` 23 | } 24 | -------------------------------------------------------------------------------- /swarm_init.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types/swarm" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // SwarmInit initializes the swarm. 11 | func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) { 12 | serverResp, err := cli.post(ctx, "/swarm/init", nil, req, nil) 13 | if err != nil { 14 | return "", err 15 | } 16 | 17 | var response string 18 | err = json.NewDecoder(serverResp.body).Decode(&response) 19 | ensureReaderClosed(serverResp) 20 | return response, err 21 | } 22 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ServerVersion returns information of the docker client and server host. 11 | func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) { 12 | resp, err := cli.get(ctx, "/version", nil, nil) 13 | if err != nil { 14 | return types.Version{}, err 15 | } 16 | 17 | var server types.Version 18 | err = json.NewDecoder(resp.body).Decode(&server) 19 | ensureReaderClosed(resp) 20 | return server, err 21 | } 22 | -------------------------------------------------------------------------------- /api/types/container/container_wait.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // ContainerWaitOKBody container wait o k body 11 | // swagger:model ContainerWaitOKBody 12 | type ContainerWaitOKBody struct { 13 | 14 | // Exit code of the container 15 | // Required: true 16 | StatusCode int64 `json:"StatusCode"` 17 | } 18 | -------------------------------------------------------------------------------- /api/types/plugin_env.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // PluginEnv plugin env 7 | // swagger:model PluginEnv 8 | type PluginEnv struct { 9 | 10 | // description 11 | // Required: true 12 | Description string `json:"Description"` 13 | 14 | // name 15 | // Required: true 16 | Name string `json:"Name"` 17 | 18 | // settable 19 | // Required: true 20 | Settable []string `json:"Settable"` 21 | 22 | // value 23 | // Required: true 24 | Value *string `json:"Value"` 25 | } 26 | -------------------------------------------------------------------------------- /container_export.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ContainerExport retrieves the raw contents of a container 11 | // and returns them as an io.ReadCloser. It's up to the caller 12 | // to close the stream. 13 | func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) { 14 | serverResp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | return serverResp.body, nil 20 | } 21 | -------------------------------------------------------------------------------- /api/types/time/duration_convert_test.go: -------------------------------------------------------------------------------- 1 | package time 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestDurationToSecondsString(t *testing.T) { 9 | cases := []struct { 10 | in time.Duration 11 | expected string 12 | }{ 13 | {0 * time.Second, "0"}, 14 | {1 * time.Second, "1"}, 15 | {1 * time.Minute, "60"}, 16 | {24 * time.Hour, "86400"}, 17 | } 18 | 19 | for _, c := range cases { 20 | s := DurationToSecondsString(c.in) 21 | if s != c.expected { 22 | t.Errorf("wrong value for input `%v`: expected `%s`, got `%s`", c.in, c.expected, s) 23 | t.Fail() 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /image_save.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ImageSave retrieves one or more images from the docker host as an io.ReadCloser. 11 | // It's up to the caller to store the images and close the stream. 12 | func (cli *Client) ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) { 13 | query := url.Values{ 14 | "names": imageIDs, 15 | } 16 | 17 | resp, err := cli.get(ctx, "/images/get", query, nil) 18 | if err != nil { 19 | return nil, err 20 | } 21 | return resp.body, nil 22 | } 23 | -------------------------------------------------------------------------------- /api/types/plugin_device.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // PluginDevice plugin device 7 | // swagger:model PluginDevice 8 | type PluginDevice struct { 9 | 10 | // description 11 | // Required: true 12 | Description string `json:"Description"` 13 | 14 | // name 15 | // Required: true 16 | Name string `json:"Name"` 17 | 18 | // path 19 | // Required: true 20 | Path *string `json:"Path"` 21 | 22 | // settable 23 | // Required: true 24 | Settable []string `json:"Settable"` 25 | } 26 | -------------------------------------------------------------------------------- /network_connect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "docker.io/go-docker/api/types" 5 | "docker.io/go-docker/api/types/network" 6 | "golang.org/x/net/context" 7 | ) 8 | 9 | // NetworkConnect connects a container to an existent network in the docker host. 10 | func (cli *Client) NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error { 11 | nc := types.NetworkConnect{ 12 | Container: containerID, 13 | EndpointConfig: config, 14 | } 15 | resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, nc, nil) 16 | ensureReaderClosed(resp) 17 | return err 18 | } 19 | -------------------------------------------------------------------------------- /volume_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types/versions" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // VolumeRemove removes a volume from the docker host. 11 | func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool) error { 12 | query := url.Values{} 13 | if versions.GreaterThanOrEqualTo(cli.version, "1.25") { 14 | if force { 15 | query.Set("force", "1") 16 | } 17 | } 18 | resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil) 19 | ensureReaderClosed(resp) 20 | return wrapResponseError(err, resp, "volume", volumeID) 21 | } 22 | -------------------------------------------------------------------------------- /swarm_get_unlock_key.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // SwarmGetUnlockKey retrieves the swarm's unlock key. 11 | func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) { 12 | serverResp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil) 13 | if err != nil { 14 | return types.SwarmUnlockKeyResponse{}, err 15 | } 16 | 17 | var response types.SwarmUnlockKeyResponse 18 | err = json.NewDecoder(serverResp.body).Decode(&response) 19 | ensureReaderClosed(serverResp) 20 | return response, err 21 | } 22 | -------------------------------------------------------------------------------- /volume_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types" 7 | volumetypes "docker.io/go-docker/api/types/volume" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // VolumeCreate creates a volume in the docker host. 12 | func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumesCreateBody) (types.Volume, error) { 13 | var volume types.Volume 14 | resp, err := cli.post(ctx, "/volumes/create", nil, options, nil) 15 | if err != nil { 16 | return volume, err 17 | } 18 | err = json.NewDecoder(resp.body).Decode(&volume) 19 | ensureReaderClosed(resp) 20 | return volume, err 21 | } 22 | -------------------------------------------------------------------------------- /api/types/filters/example_test.go: -------------------------------------------------------------------------------- 1 | package filters 2 | 3 | func ExampleArgs_MatchKVList() { 4 | args := NewArgs( 5 | Arg("label", "image=foo"), 6 | Arg("label", "state=running")) 7 | 8 | // returns true because there are no values for bogus 9 | args.MatchKVList("bogus", nil) 10 | 11 | // returns false because there are no sources 12 | args.MatchKVList("label", nil) 13 | 14 | // returns true because all sources are matched 15 | args.MatchKVList("label", map[string]string{ 16 | "image": "foo", 17 | "state": "running", 18 | }) 19 | 20 | // returns false because the values do not match 21 | args.MatchKVList("label", map[string]string{ 22 | "image": "other", 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /checkpoint_delete.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // CheckpointDelete deletes the checkpoint with the given name from the given container 11 | func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options types.CheckpointDeleteOptions) error { 12 | query := url.Values{} 13 | if options.CheckpointDir != "" { 14 | query.Set("dir", options.CheckpointDir) 15 | } 16 | 17 | resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+options.CheckpointID, query, nil) 18 | ensureReaderClosed(resp) 19 | return err 20 | } 21 | -------------------------------------------------------------------------------- /config_update.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | 7 | "docker.io/go-docker/api/types/swarm" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ConfigUpdate attempts to update a Config 12 | func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error { 13 | if err := cli.NewVersionError("1.30", "config update"); err != nil { 14 | return err 15 | } 16 | query := url.Values{} 17 | query.Set("version", strconv.FormatUint(version.Index, 10)) 18 | resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil) 19 | ensureReaderClosed(resp) 20 | return err 21 | } 22 | -------------------------------------------------------------------------------- /secret_update.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | 7 | "docker.io/go-docker/api/types/swarm" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // SecretUpdate attempts to update a Secret 12 | func (cli *Client) SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error { 13 | if err := cli.NewVersionError("1.25", "secret update"); err != nil { 14 | return err 15 | } 16 | query := url.Values{} 17 | query.Set("version", strconv.FormatUint(version.Index, 10)) 18 | resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, secret, nil) 19 | ensureReaderClosed(resp) 20 | return err 21 | } 22 | -------------------------------------------------------------------------------- /interface_experimental.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "docker.io/go-docker/api/types" 5 | "golang.org/x/net/context" 6 | ) 7 | 8 | type apiClientExperimental interface { 9 | CheckpointAPIClient 10 | } 11 | 12 | // CheckpointAPIClient defines API client methods for the checkpoints 13 | type CheckpointAPIClient interface { 14 | CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error 15 | CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error 16 | CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) 17 | } 18 | -------------------------------------------------------------------------------- /api/types/swarm/runtime.go: -------------------------------------------------------------------------------- 1 | package swarm 2 | 3 | // RuntimeType is the type of runtime used for the TaskSpec 4 | type RuntimeType string 5 | 6 | // RuntimeURL is the proto type url 7 | type RuntimeURL string 8 | 9 | const ( 10 | // RuntimeContainer is the container based runtime 11 | RuntimeContainer RuntimeType = "container" 12 | // RuntimePlugin is the plugin based runtime 13 | RuntimePlugin RuntimeType = "plugin" 14 | 15 | // RuntimeURLContainer is the proto url for the container type 16 | RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer" 17 | // RuntimeURLPlugin is the proto url for the plugin type 18 | RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin" 19 | ) 20 | -------------------------------------------------------------------------------- /image_history.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types/image" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ImageHistory returns the changes in an image in history format. 12 | func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) { 13 | var history []image.HistoryResponseItem 14 | serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil) 15 | if err != nil { 16 | return history, err 17 | } 18 | 19 | err = json.NewDecoder(serverResp.body).Decode(&history) 20 | ensureReaderClosed(serverResp) 21 | return history, err 22 | } 23 | -------------------------------------------------------------------------------- /info.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/url" 7 | 8 | "docker.io/go-docker/api/types" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // Info returns information about the docker server. 13 | func (cli *Client) Info(ctx context.Context) (types.Info, error) { 14 | var info types.Info 15 | serverResp, err := cli.get(ctx, "/info", url.Values{}, nil) 16 | if err != nil { 17 | return info, err 18 | } 19 | defer ensureReaderClosed(serverResp) 20 | 21 | if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil { 22 | return info, fmt.Errorf("Error reading remote info: %v", err) 23 | } 24 | 25 | return info, nil 26 | } 27 | -------------------------------------------------------------------------------- /disk_usage.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "docker.io/go-docker/api/types" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // DiskUsage requests the current data usage from the daemon 12 | func (cli *Client) DiskUsage(ctx context.Context) (types.DiskUsage, error) { 13 | var du types.DiskUsage 14 | 15 | serverResp, err := cli.get(ctx, "/system/df", nil, nil) 16 | if err != nil { 17 | return du, err 18 | } 19 | defer ensureReaderClosed(serverResp) 20 | 21 | if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil { 22 | return du, fmt.Errorf("Error retrieving disk usage: %v", err) 23 | } 24 | 25 | return du, nil 26 | } 27 | -------------------------------------------------------------------------------- /api/types/container/container_changes.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // ContainerChangeResponseItem container change response item 11 | // swagger:model ContainerChangeResponseItem 12 | type ContainerChangeResponseItem struct { 13 | 14 | // Kind of change 15 | // Required: true 16 | Kind uint8 `json:"Kind"` 17 | 18 | // Path to file that has changed 19 | // Required: true 20 | Path string `json:"Path"` 21 | } 22 | -------------------------------------------------------------------------------- /container_stop.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "time" 6 | 7 | timetypes "docker.io/go-docker/api/types/time" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ContainerStop stops a container without terminating the process. 12 | // The process is blocked until the container stops or the timeout expires. 13 | func (cli *Client) ContainerStop(ctx context.Context, containerID string, timeout *time.Duration) error { 14 | query := url.Values{} 15 | if timeout != nil { 16 | query.Set("t", timetypes.DurationToSecondsString(*timeout)) 17 | } 18 | resp, err := cli.post(ctx, "/containers/"+containerID+"/stop", query, nil, nil) 19 | ensureReaderClosed(resp) 20 | return err 21 | } 22 | -------------------------------------------------------------------------------- /api/types/swarm/config.go: -------------------------------------------------------------------------------- 1 | package swarm 2 | 3 | import "os" 4 | 5 | // Config represents a config. 6 | type Config struct { 7 | ID string 8 | Meta 9 | Spec ConfigSpec 10 | } 11 | 12 | // ConfigSpec represents a config specification from a config in swarm 13 | type ConfigSpec struct { 14 | Annotations 15 | Data []byte `json:",omitempty"` 16 | } 17 | 18 | // ConfigReferenceFileTarget is a file target in a config reference 19 | type ConfigReferenceFileTarget struct { 20 | Name string 21 | UID string 22 | GID string 23 | Mode os.FileMode 24 | } 25 | 26 | // ConfigReference is a reference to a config in swarm 27 | type ConfigReference struct { 28 | File *ConfigReferenceFileTarget 29 | ConfigID string 30 | ConfigName string 31 | } 32 | -------------------------------------------------------------------------------- /api/types/registry/authenticate.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // AuthenticateOKBody authenticate o k body 11 | // swagger:model AuthenticateOKBody 12 | type AuthenticateOKBody struct { 13 | 14 | // An opaque token used to authenticate a user after a successful login 15 | // Required: true 16 | IdentityToken string `json:"IdentityToken"` 17 | 18 | // The status of the authentication 19 | // Required: true 20 | Status string `json:"Status"` 21 | } 22 | -------------------------------------------------------------------------------- /plugin_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "net/url" 7 | 8 | "docker.io/go-docker/api/types" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // PluginCreate creates a plugin 13 | func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error { 14 | headers := http.Header(make(map[string][]string)) 15 | headers.Set("Content-Type", "application/x-tar") 16 | 17 | query := url.Values{} 18 | query.Set("name", createOptions.RepoName) 19 | 20 | resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers) 21 | if err != nil { 22 | return err 23 | } 24 | ensureReaderClosed(resp) 25 | return err 26 | } 27 | -------------------------------------------------------------------------------- /api/types/container/container_create.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // ContainerCreateCreatedBody container create created body 11 | // swagger:model ContainerCreateCreatedBody 12 | type ContainerCreateCreatedBody struct { 13 | 14 | // The ID of the created container 15 | // Required: true 16 | ID string `json:"Id"` 17 | 18 | // Warnings encountered when creating the container 19 | // Required: true 20 | Warnings []string `json:"Warnings"` 21 | } 22 | -------------------------------------------------------------------------------- /container_update.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types/container" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ContainerUpdate updates resources of a container 11 | func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) { 12 | var response container.ContainerUpdateOKBody 13 | serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil) 14 | if err != nil { 15 | return response, err 16 | } 17 | 18 | err = json.NewDecoder(serverResp.body).Decode(&response) 19 | 20 | ensureReaderClosed(serverResp) 21 | return response, err 22 | } 23 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | 2 | [[constraint]] 3 | name = "github.com/docker/distribution" 4 | revision = "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c" 5 | 6 | [[constraint]] 7 | name = "github.com/docker/go-connections" 8 | version = "0.3.0" 9 | 10 | [[constraint]] 11 | name = "github.com/docker/go-units" 12 | version = "0.3.2" 13 | 14 | [[constraint]] 15 | name = "github.com/gogo/protobuf" 16 | version = "0.4.0" 17 | 18 | [[constraint]] 19 | name = "github.com/opencontainers/go-digest" 20 | version = "1.0.0-rc1" 21 | 22 | [[constraint]] 23 | name = "github.com/opencontainers/image-spec" 24 | version = "1.0.0" 25 | 26 | [[constraint]] 27 | name = "github.com/pkg/errors" 28 | version = "0.8.0" 29 | 30 | [[constraint]] 31 | name = "golang.org/x/net" 32 | -------------------------------------------------------------------------------- /container_start.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "golang.org/x/net/context" 7 | 8 | "docker.io/go-docker/api/types" 9 | ) 10 | 11 | // ContainerStart sends a request to the docker daemon to start a container. 12 | func (cli *Client) ContainerStart(ctx context.Context, containerID string, options types.ContainerStartOptions) error { 13 | query := url.Values{} 14 | if len(options.CheckpointID) != 0 { 15 | query.Set("checkpoint", options.CheckpointID) 16 | } 17 | if len(options.CheckpointDir) != 0 { 18 | query.Set("checkpoint-dir", options.CheckpointDir) 19 | } 20 | 21 | resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil) 22 | ensureReaderClosed(resp) 23 | return err 24 | } 25 | -------------------------------------------------------------------------------- /api/types/volume/volumes_list.go: -------------------------------------------------------------------------------- 1 | package volume 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | import "docker.io/go-docker/api/types" 11 | 12 | // VolumesListOKBody volumes list o k body 13 | // swagger:model VolumesListOKBody 14 | type VolumesListOKBody struct { 15 | 16 | // List of volumes 17 | // Required: true 18 | Volumes []*types.Volume `json:"Volumes"` 19 | 20 | // Warnings that occurred when fetching the list of volumes 21 | // Required: true 22 | Warnings []string `json:"Warnings"` 23 | } 24 | -------------------------------------------------------------------------------- /container_diff.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types/container" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ContainerDiff shows differences in a container filesystem since it was started. 12 | func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]container.ContainerChangeResponseItem, error) { 13 | var changes []container.ContainerChangeResponseItem 14 | 15 | serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil) 16 | if err != nil { 17 | return changes, err 18 | } 19 | 20 | err = json.NewDecoder(serverResp.body).Decode(&changes) 21 | ensureReaderClosed(serverResp) 22 | return changes, err 23 | } 24 | -------------------------------------------------------------------------------- /container_restart.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "time" 6 | 7 | timetypes "docker.io/go-docker/api/types/time" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ContainerRestart stops and starts a container again. 12 | // It makes the daemon to wait for the container to be up again for 13 | // a specific amount of time, given the timeout. 14 | func (cli *Client) ContainerRestart(ctx context.Context, containerID string, timeout *time.Duration) error { 15 | query := url.Values{} 16 | if timeout != nil { 17 | query.Set("t", timetypes.DurationToSecondsString(*timeout)) 18 | } 19 | resp, err := cli.post(ctx, "/containers/"+containerID+"/restart", query, nil, nil) 20 | ensureReaderClosed(resp) 21 | return err 22 | } 23 | -------------------------------------------------------------------------------- /api/types/container/container_top.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // ContainerTopOKBody container top o k body 11 | // swagger:model ContainerTopOKBody 12 | type ContainerTopOKBody struct { 13 | 14 | // Each process running in the container, where each is process is an array of values corresponding to the titles 15 | // Required: true 16 | Processes [][]string `json:"Processes"` 17 | 18 | // The ps column titles 19 | // Required: true 20 | Titles []string `json:"Titles"` 21 | } 22 | -------------------------------------------------------------------------------- /config_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types" 7 | "docker.io/go-docker/api/types/swarm" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ConfigCreate creates a new Config. 12 | func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (types.ConfigCreateResponse, error) { 13 | var response types.ConfigCreateResponse 14 | if err := cli.NewVersionError("1.30", "config create"); err != nil { 15 | return response, err 16 | } 17 | resp, err := cli.post(ctx, "/configs/create", nil, config, nil) 18 | if err != nil { 19 | return response, err 20 | } 21 | 22 | err = json.NewDecoder(resp.body).Decode(&response) 23 | ensureReaderClosed(resp) 24 | return response, err 25 | } 26 | -------------------------------------------------------------------------------- /container_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ContainerRemove kills and removes a container from the docker host. 11 | func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options types.ContainerRemoveOptions) error { 12 | query := url.Values{} 13 | if options.RemoveVolumes { 14 | query.Set("v", "1") 15 | } 16 | if options.RemoveLinks { 17 | query.Set("link", "1") 18 | } 19 | 20 | if options.Force { 21 | query.Set("force", "1") 22 | } 23 | 24 | resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil) 25 | ensureReaderClosed(resp) 26 | return wrapResponseError(err, resp, "container", containerID) 27 | } 28 | -------------------------------------------------------------------------------- /secret_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types" 7 | "docker.io/go-docker/api/types/swarm" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // SecretCreate creates a new Secret. 12 | func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error) { 13 | var response types.SecretCreateResponse 14 | if err := cli.NewVersionError("1.25", "secret create"); err != nil { 15 | return response, err 16 | } 17 | resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil) 18 | if err != nil { 19 | return response, err 20 | } 21 | 22 | err = json.NewDecoder(resp.body).Decode(&response) 23 | ensureReaderClosed(resp) 24 | return response, err 25 | } 26 | -------------------------------------------------------------------------------- /plugin_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | 8 | "docker.io/go-docker/api/types" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // PluginInspectWithRaw inspects an existing plugin 13 | func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { 14 | resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil) 15 | if err != nil { 16 | return nil, nil, wrapResponseError(err, resp, "plugin", name) 17 | } 18 | 19 | defer ensureReaderClosed(resp) 20 | body, err := ioutil.ReadAll(resp.body) 21 | if err != nil { 22 | return nil, nil, err 23 | } 24 | var p types.Plugin 25 | rdr := bytes.NewReader(body) 26 | err = json.NewDecoder(rdr).Decode(&p) 27 | return &p, body, err 28 | } 29 | -------------------------------------------------------------------------------- /network_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // NetworkCreate creates a new network in the docker host. 11 | func (cli *Client) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) { 12 | networkCreateRequest := types.NetworkCreateRequest{ 13 | NetworkCreate: options, 14 | Name: name, 15 | } 16 | var response types.NetworkCreateResponse 17 | serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil) 18 | if err != nil { 19 | return response, err 20 | } 21 | 22 | json.NewDecoder(serverResp.body).Decode(&response) 23 | ensureReaderClosed(serverResp) 24 | return response, err 25 | } 26 | -------------------------------------------------------------------------------- /swarm_update.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "strconv" 7 | 8 | "docker.io/go-docker/api/types/swarm" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // SwarmUpdate updates the swarm. 13 | func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags swarm.UpdateFlags) error { 14 | query := url.Values{} 15 | query.Set("version", strconv.FormatUint(version.Index, 10)) 16 | query.Set("rotateWorkerToken", fmt.Sprintf("%v", flags.RotateWorkerToken)) 17 | query.Set("rotateManagerToken", fmt.Sprintf("%v", flags.RotateManagerToken)) 18 | query.Set("rotateManagerUnlockKey", fmt.Sprintf("%v", flags.RotateManagerUnlockKey)) 19 | resp, err := cli.post(ctx, "/swarm/update", query, swarm, nil) 20 | ensureReaderClosed(resp) 21 | return err 22 | } 23 | -------------------------------------------------------------------------------- /container_stats.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ContainerStats returns near realtime stats for a given container. 11 | // It's up to the caller to close the io.ReadCloser returned. 12 | func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) { 13 | query := url.Values{} 14 | query.Set("stream", "0") 15 | if stream { 16 | query.Set("stream", "1") 17 | } 18 | 19 | resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) 20 | if err != nil { 21 | return types.ContainerStats{}, err 22 | } 23 | 24 | osType := getDockerOS(resp.header.Get("Server")) 25 | return types.ContainerStats{Body: resp.body, OSType: osType}, err 26 | } 27 | -------------------------------------------------------------------------------- /api/types/auth.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // AuthConfig contains authorization information for connecting to a Registry 4 | type AuthConfig struct { 5 | Username string `json:"username,omitempty"` 6 | Password string `json:"password,omitempty"` 7 | Auth string `json:"auth,omitempty"` 8 | 9 | // Email is an optional value associated with the username. 10 | // This field is deprecated and will be removed in a later 11 | // version of docker. 12 | Email string `json:"email,omitempty"` 13 | 14 | ServerAddress string `json:"serveraddress,omitempty"` 15 | 16 | // IdentityToken is used to authenticate the user and get 17 | // an access token for the registry. 18 | IdentityToken string `json:"identitytoken,omitempty"` 19 | 20 | // RegistryToken is a bearer token to be sent to a registry 21 | RegistryToken string `json:"registrytoken,omitempty"` 22 | } 23 | -------------------------------------------------------------------------------- /container_top.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | "strings" 7 | 8 | "docker.io/go-docker/api/types/container" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // ContainerTop shows process information from within a container. 13 | func (cli *Client) ContainerTop(ctx context.Context, containerID string, arguments []string) (container.ContainerTopOKBody, error) { 14 | var response container.ContainerTopOKBody 15 | query := url.Values{} 16 | if len(arguments) > 0 { 17 | query.Set("ps_args", strings.Join(arguments, " ")) 18 | } 19 | 20 | resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil) 21 | if err != nil { 22 | return response, err 23 | } 24 | 25 | err = json.NewDecoder(resp.body).Decode(&response) 26 | ensureReaderClosed(resp) 27 | return response, err 28 | } 29 | -------------------------------------------------------------------------------- /api/types/versions/compare_test.go: -------------------------------------------------------------------------------- 1 | package versions 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func assertVersion(t *testing.T, a, b string, result int) { 8 | if r := compare(a, b); r != result { 9 | t.Fatalf("Unexpected version comparison result. Found %d, expected %d", r, result) 10 | } 11 | } 12 | 13 | func TestCompareVersion(t *testing.T) { 14 | assertVersion(t, "1.12", "1.12", 0) 15 | assertVersion(t, "1.0.0", "1", 0) 16 | assertVersion(t, "1", "1.0.0", 0) 17 | assertVersion(t, "1.05.00.0156", "1.0.221.9289", 1) 18 | assertVersion(t, "1", "1.0.1", -1) 19 | assertVersion(t, "1.0.1", "1", 1) 20 | assertVersion(t, "1.0.1", "1.0.2", -1) 21 | assertVersion(t, "1.0.2", "1.0.3", -1) 22 | assertVersion(t, "1.0.3", "1.1", -1) 23 | assertVersion(t, "1.1", "1.1.1", -1) 24 | assertVersion(t, "1.1.1", "1.1.2", -1) 25 | assertVersion(t, "1.1.2", "1.2", -1) 26 | } 27 | -------------------------------------------------------------------------------- /api/types/plugin_mount.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // PluginMount plugin mount 7 | // swagger:model PluginMount 8 | type PluginMount struct { 9 | 10 | // description 11 | // Required: true 12 | Description string `json:"Description"` 13 | 14 | // destination 15 | // Required: true 16 | Destination string `json:"Destination"` 17 | 18 | // name 19 | // Required: true 20 | Name string `json:"Name"` 21 | 22 | // options 23 | // Required: true 24 | Options []string `json:"Options"` 25 | 26 | // settable 27 | // Required: true 28 | Settable []string `json:"Settable"` 29 | 30 | // source 31 | // Required: true 32 | Source *string `json:"Source"` 33 | 34 | // type 35 | // Required: true 36 | Type string `json:"Type"` 37 | } 38 | -------------------------------------------------------------------------------- /api/types/swarm/secret.go: -------------------------------------------------------------------------------- 1 | package swarm 2 | 3 | import "os" 4 | 5 | // Secret represents a secret. 6 | type Secret struct { 7 | ID string 8 | Meta 9 | Spec SecretSpec 10 | } 11 | 12 | // SecretSpec represents a secret specification from a secret in swarm 13 | type SecretSpec struct { 14 | Annotations 15 | Data []byte `json:",omitempty"` 16 | Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store 17 | } 18 | 19 | // SecretReferenceFileTarget is a file target in a secret reference 20 | type SecretReferenceFileTarget struct { 21 | Name string 22 | UID string 23 | GID string 24 | Mode os.FileMode 25 | } 26 | 27 | // SecretReference is a reference to a secret in swarm 28 | type SecretReference struct { 29 | File *SecretReferenceFileTarget 30 | SecretID string 31 | SecretName string 32 | } 33 | -------------------------------------------------------------------------------- /node_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | 8 | "docker.io/go-docker/api/types/swarm" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // NodeInspectWithRaw returns the node information. 13 | func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) { 14 | serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil) 15 | if err != nil { 16 | return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID) 17 | } 18 | defer ensureReaderClosed(serverResp) 19 | 20 | body, err := ioutil.ReadAll(serverResp.body) 21 | if err != nil { 22 | return swarm.Node{}, nil, err 23 | } 24 | 25 | var response swarm.Node 26 | rdr := bytes.NewReader(body) 27 | err = json.NewDecoder(rdr).Decode(&response) 28 | return response, body, err 29 | } 30 | -------------------------------------------------------------------------------- /image_remove.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ImageRemove removes an image from the docker host. 12 | func (cli *Client) ImageRemove(ctx context.Context, imageID string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) { 13 | query := url.Values{} 14 | 15 | if options.Force { 16 | query.Set("force", "1") 17 | } 18 | if !options.PruneChildren { 19 | query.Set("noprune", "1") 20 | } 21 | 22 | var dels []types.ImageDeleteResponseItem 23 | resp, err := cli.delete(ctx, "/images/"+imageID, query, nil) 24 | if err != nil { 25 | return dels, wrapResponseError(err, resp, "image", imageID) 26 | } 27 | 28 | err = json.NewDecoder(resp.body).Decode(&dels) 29 | ensureReaderClosed(resp) 30 | return dels, err 31 | } 32 | -------------------------------------------------------------------------------- /task_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | 8 | "docker.io/go-docker/api/types/swarm" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // TaskInspectWithRaw returns the task information and its raw representation.. 13 | func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) { 14 | serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil) 15 | if err != nil { 16 | return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID) 17 | } 18 | defer ensureReaderClosed(serverResp) 19 | 20 | body, err := ioutil.ReadAll(serverResp.body) 21 | if err != nil { 22 | return swarm.Task{}, nil, err 23 | } 24 | 25 | var response swarm.Task 26 | rdr := bytes.NewReader(body) 27 | err = json.NewDecoder(rdr).Decode(&response) 28 | return response, body, err 29 | } 30 | -------------------------------------------------------------------------------- /api/types/strslice/strslice.go: -------------------------------------------------------------------------------- 1 | package strslice 2 | 3 | import "encoding/json" 4 | 5 | // StrSlice represents a string or an array of strings. 6 | // We need to override the json decoder to accept both options. 7 | type StrSlice []string 8 | 9 | // UnmarshalJSON decodes the byte slice whether it's a string or an array of 10 | // strings. This method is needed to implement json.Unmarshaler. 11 | func (e *StrSlice) UnmarshalJSON(b []byte) error { 12 | if len(b) == 0 { 13 | // With no input, we preserve the existing value by returning nil and 14 | // leaving the target alone. This allows defining default values for 15 | // the type. 16 | return nil 17 | } 18 | 19 | p := make([]string, 0, 1) 20 | if err := json.Unmarshal(b, &p); err != nil { 21 | var s string 22 | if err := json.Unmarshal(b, &s); err != nil { 23 | return err 24 | } 25 | p = append(p, s) 26 | } 27 | 28 | *e = p 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /api/types/container/waitcondition.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | // WaitCondition is a type used to specify a container state for which 4 | // to wait. 5 | type WaitCondition string 6 | 7 | // Possible WaitCondition Values. 8 | // 9 | // WaitConditionNotRunning (default) is used to wait for any of the non-running 10 | // states: "created", "exited", "dead", "removing", or "removed". 11 | // 12 | // WaitConditionNextExit is used to wait for the next time the state changes 13 | // to a non-running state. If the state is currently "created" or "exited", 14 | // this would cause Wait() to block until either the container runs and exits 15 | // or is removed. 16 | // 17 | // WaitConditionRemoved is used to wait for the container to be removed. 18 | const ( 19 | WaitConditionNotRunning WaitCondition = "not-running" 20 | WaitConditionNextExit WaitCondition = "next-exit" 21 | WaitConditionRemoved WaitCondition = "removed" 22 | ) 23 | -------------------------------------------------------------------------------- /checkpoint_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // CheckpointList returns the checkpoints of the given container in the docker host 12 | func (cli *Client) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { 13 | var checkpoints []types.Checkpoint 14 | 15 | query := url.Values{} 16 | if options.CheckpointDir != "" { 17 | query.Set("dir", options.CheckpointDir) 18 | } 19 | 20 | resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) 21 | if err != nil { 22 | return checkpoints, wrapResponseError(err, resp, "container", container) 23 | } 24 | 25 | err = json.NewDecoder(resp.body).Decode(&checkpoints) 26 | ensureReaderClosed(resp) 27 | return checkpoints, err 28 | } 29 | -------------------------------------------------------------------------------- /task_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "docker.io/go-docker/api/types/swarm" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // TaskList returns the list of tasks. 14 | func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) { 15 | query := url.Values{} 16 | 17 | if options.Filters.Len() > 0 { 18 | filterJSON, err := filters.ToJSON(options.Filters) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | query.Set("filters", filterJSON) 24 | } 25 | 26 | resp, err := cli.get(ctx, "/tasks", query, nil) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | var tasks []swarm.Task 32 | err = json.NewDecoder(resp.body).Decode(&tasks) 33 | ensureReaderClosed(resp) 34 | return tasks, err 35 | } 36 | -------------------------------------------------------------------------------- /node_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "docker.io/go-docker/api/types/swarm" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // NodeList returns the list of nodes. 14 | func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { 15 | query := url.Values{} 16 | 17 | if options.Filters.Len() > 0 { 18 | filterJSON, err := filters.ToJSON(options.Filters) 19 | 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | query.Set("filters", filterJSON) 25 | } 26 | 27 | resp, err := cli.get(ctx, "/nodes", query, nil) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | var nodes []swarm.Node 33 | err = json.NewDecoder(resp.body).Decode(&nodes) 34 | ensureReaderClosed(resp) 35 | return nodes, err 36 | } 37 | -------------------------------------------------------------------------------- /image_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | 8 | "docker.io/go-docker/api/types" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // ImageInspectWithRaw returns the image information and its raw representation. 13 | func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) { 14 | serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil) 15 | if err != nil { 16 | return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID) 17 | } 18 | defer ensureReaderClosed(serverResp) 19 | 20 | body, err := ioutil.ReadAll(serverResp.body) 21 | if err != nil { 22 | return types.ImageInspect{}, nil, err 23 | } 24 | 25 | var response types.ImageInspect 26 | rdr := bytes.NewReader(body) 27 | err = json.NewDecoder(rdr).Decode(&response) 28 | return response, body, err 29 | } 30 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "regexp" 6 | 7 | "docker.io/go-docker/api/types/filters" 8 | ) 9 | 10 | var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`) 11 | 12 | // getDockerOS returns the operating system based on the server header from the daemon. 13 | func getDockerOS(serverHeader string) string { 14 | var osType string 15 | matches := headerRegexp.FindStringSubmatch(serverHeader) 16 | if len(matches) > 0 { 17 | osType = matches[1] 18 | } 19 | return osType 20 | } 21 | 22 | // getFiltersQuery returns a url query with "filters" query term, based on the 23 | // filters provided. 24 | func getFiltersQuery(f filters.Args) (url.Values, error) { 25 | query := url.Values{} 26 | if f.Len() > 0 { 27 | filterJSON, err := filters.ToJSON(f) 28 | if err != nil { 29 | return query, err 30 | } 31 | query.Set("filters", filterJSON) 32 | } 33 | return query, nil 34 | } 35 | -------------------------------------------------------------------------------- /image_load.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | 7 | "golang.org/x/net/context" 8 | 9 | "docker.io/go-docker/api/types" 10 | ) 11 | 12 | // ImageLoad loads an image in the docker host from the client host. 13 | // It's up to the caller to close the io.ReadCloser in the 14 | // ImageLoadResponse returned by this function. 15 | func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) { 16 | v := url.Values{} 17 | v.Set("quiet", "0") 18 | if quiet { 19 | v.Set("quiet", "1") 20 | } 21 | headers := map[string][]string{"Content-Type": {"application/x-tar"}} 22 | resp, err := cli.postRaw(ctx, "/images/load", v, input, headers) 23 | if err != nil { 24 | return types.ImageLoadResponse{}, err 25 | } 26 | return types.ImageLoadResponse{ 27 | Body: resp.body, 28 | JSON: resp.header.Get("Content-Type") == "application/json", 29 | }, nil 30 | } 31 | -------------------------------------------------------------------------------- /plugin_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // PluginList returns the installed plugins 13 | func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error) { 14 | var plugins types.PluginsListResponse 15 | query := url.Values{} 16 | 17 | if filter.Len() > 0 { 18 | filterJSON, err := filters.ToParamWithVersion(cli.version, filter) 19 | if err != nil { 20 | return plugins, err 21 | } 22 | query.Set("filters", filterJSON) 23 | } 24 | resp, err := cli.get(ctx, "/plugins", query, nil) 25 | if err != nil { 26 | return plugins, wrapResponseError(err, resp, "plugin", "") 27 | } 28 | 29 | err = json.NewDecoder(resp.body).Decode(&plugins) 30 | ensureReaderClosed(resp) 31 | return plugins, err 32 | } 33 | -------------------------------------------------------------------------------- /service_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "docker.io/go-docker/api/types/swarm" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // ServiceList returns the list of services. 14 | func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { 15 | query := url.Values{} 16 | 17 | if options.Filters.Len() > 0 { 18 | filterJSON, err := filters.ToJSON(options.Filters) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | query.Set("filters", filterJSON) 24 | } 25 | 26 | resp, err := cli.get(ctx, "/services", query, nil) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | var services []swarm.Service 32 | err = json.NewDecoder(resp.body).Decode(&services) 33 | ensureReaderClosed(resp) 34 | return services, err 35 | } 36 | -------------------------------------------------------------------------------- /api/types/image/image_history.go: -------------------------------------------------------------------------------- 1 | package image 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // HistoryResponseItem history response item 11 | // swagger:model HistoryResponseItem 12 | type HistoryResponseItem struct { 13 | 14 | // comment 15 | // Required: true 16 | Comment string `json:"Comment"` 17 | 18 | // created 19 | // Required: true 20 | Created int64 `json:"Created"` 21 | 22 | // created by 23 | // Required: true 24 | CreatedBy string `json:"CreatedBy"` 25 | 26 | // Id 27 | // Required: true 28 | ID string `json:"Id"` 29 | 30 | // size 31 | // Required: true 32 | Size int64 `json:"Size"` 33 | 34 | // tags 35 | // Required: true 36 | Tags []string `json:"Tags"` 37 | } 38 | -------------------------------------------------------------------------------- /login.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "net/url" 7 | 8 | "docker.io/go-docker/api/types" 9 | "docker.io/go-docker/api/types/registry" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // RegistryLogin authenticates the docker server with a given docker registry. 14 | // It returns unauthorizedError when the authentication fails. 15 | func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) { 16 | resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil) 17 | 18 | if resp.statusCode == http.StatusUnauthorized { 19 | return registry.AuthenticateOKBody{}, unauthorizedError{err} 20 | } 21 | if err != nil { 22 | return registry.AuthenticateOKBody{}, err 23 | } 24 | 25 | var response registry.AuthenticateOKBody 26 | err = json.NewDecoder(resp.body).Decode(&response) 27 | ensureReaderClosed(resp) 28 | return response, err 29 | } 30 | -------------------------------------------------------------------------------- /volume_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types/filters" 8 | volumetypes "docker.io/go-docker/api/types/volume" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // VolumeList returns the volumes configured in the docker host. 13 | func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumesListOKBody, error) { 14 | var volumes volumetypes.VolumesListOKBody 15 | query := url.Values{} 16 | 17 | if filter.Len() > 0 { 18 | filterJSON, err := filters.ToParamWithVersion(cli.version, filter) 19 | if err != nil { 20 | return volumes, err 21 | } 22 | query.Set("filters", filterJSON) 23 | } 24 | resp, err := cli.get(ctx, "/volumes", query, nil) 25 | if err != nil { 26 | return volumes, err 27 | } 28 | 29 | err = json.NewDecoder(resp.body).Decode(&volumes) 30 | ensureReaderClosed(resp) 31 | return volumes, err 32 | } 33 | -------------------------------------------------------------------------------- /ping.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "path" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers 11 | func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { 12 | var ping types.Ping 13 | req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) 14 | if err != nil { 15 | return ping, err 16 | } 17 | serverResp, err := cli.doRequest(ctx, req) 18 | if err != nil { 19 | return ping, err 20 | } 21 | defer ensureReaderClosed(serverResp) 22 | 23 | if serverResp.header != nil { 24 | ping.APIVersion = serverResp.header.Get("API-Version") 25 | 26 | if serverResp.header.Get("Docker-Experimental") == "true" { 27 | ping.Experimental = true 28 | } 29 | ping.OSType = serverResp.header.Get("OSType") 30 | } 31 | return ping, cli.checkResponseErr(serverResp) 32 | } 33 | -------------------------------------------------------------------------------- /config_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | 8 | "docker.io/go-docker/api/types/swarm" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // ConfigInspectWithRaw returns the config information with raw data 13 | func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) { 14 | if err := cli.NewVersionError("1.30", "config inspect"); err != nil { 15 | return swarm.Config{}, nil, err 16 | } 17 | resp, err := cli.get(ctx, "/configs/"+id, nil, nil) 18 | if err != nil { 19 | return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id) 20 | } 21 | defer ensureReaderClosed(resp) 22 | 23 | body, err := ioutil.ReadAll(resp.body) 24 | if err != nil { 25 | return swarm.Config{}, nil, err 26 | } 27 | 28 | var config swarm.Config 29 | rdr := bytes.NewReader(body) 30 | err = json.NewDecoder(rdr).Decode(&config) 31 | 32 | return config, body, err 33 | } 34 | -------------------------------------------------------------------------------- /secret_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | 8 | "docker.io/go-docker/api/types/swarm" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // SecretInspectWithRaw returns the secret information with raw data 13 | func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.Secret, []byte, error) { 14 | if err := cli.NewVersionError("1.25", "secret inspect"); err != nil { 15 | return swarm.Secret{}, nil, err 16 | } 17 | resp, err := cli.get(ctx, "/secrets/"+id, nil, nil) 18 | if err != nil { 19 | return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id) 20 | } 21 | defer ensureReaderClosed(resp) 22 | 23 | body, err := ioutil.ReadAll(resp.body) 24 | if err != nil { 25 | return swarm.Secret{}, nil, err 26 | } 27 | 28 | var secret swarm.Secret 29 | rdr := bytes.NewReader(body) 30 | err = json.NewDecoder(rdr).Decode(&secret) 31 | 32 | return secret, body, err 33 | } 34 | -------------------------------------------------------------------------------- /network_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // NetworkList returns the list of networks configured in the docker host. 13 | func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) { 14 | query := url.Values{} 15 | if options.Filters.Len() > 0 { 16 | filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | query.Set("filters", filterJSON) 22 | } 23 | var networkResources []types.NetworkResource 24 | resp, err := cli.get(ctx, "/networks", query, nil) 25 | if err != nil { 26 | return networkResources, err 27 | } 28 | err = json.NewDecoder(resp.body).Decode(&networkResources) 29 | ensureReaderClosed(resp) 30 | return networkResources, err 31 | } 32 | -------------------------------------------------------------------------------- /api/types/volume/volumes_create.go: -------------------------------------------------------------------------------- 1 | package volume 2 | 3 | // ---------------------------------------------------------------------------- 4 | // DO NOT EDIT THIS FILE 5 | // This file was generated by `swagger generate operation` 6 | // 7 | // See hack/generate-swagger-api.sh 8 | // ---------------------------------------------------------------------------- 9 | 10 | // VolumesCreateBody volumes create body 11 | // swagger:model VolumesCreateBody 12 | type VolumesCreateBody struct { 13 | 14 | // Name of the volume driver to use. 15 | // Required: true 16 | Driver string `json:"Driver"` 17 | 18 | // A mapping of driver options and values. These options are passed directly to the driver and are driver specific. 19 | // Required: true 20 | DriverOpts map[string]string `json:"DriverOpts"` 21 | 22 | // User-defined key/value metadata. 23 | // Required: true 24 | Labels map[string]string `json:"Labels"` 25 | 26 | // The new volume's name. If not specified, Docker generates a name. 27 | // Required: true 28 | Name string `json:"Name"` 29 | } 30 | -------------------------------------------------------------------------------- /config_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "docker.io/go-docker/api/types/swarm" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // ConfigList returns the list of configs. 14 | func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) { 15 | if err := cli.NewVersionError("1.30", "config list"); err != nil { 16 | return nil, err 17 | } 18 | query := url.Values{} 19 | 20 | if options.Filters.Len() > 0 { 21 | filterJSON, err := filters.ToJSON(options.Filters) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | query.Set("filters", filterJSON) 27 | } 28 | 29 | resp, err := cli.get(ctx, "/configs", query, nil) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | var configs []swarm.Config 35 | err = json.NewDecoder(resp.body).Decode(&configs) 36 | ensureReaderClosed(resp) 37 | return configs, err 38 | } 39 | -------------------------------------------------------------------------------- /image_prune.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // ImagesPrune requests the daemon to delete unused data 13 | func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (types.ImagesPruneReport, error) { 14 | var report types.ImagesPruneReport 15 | 16 | if err := cli.NewVersionError("1.25", "image prune"); err != nil { 17 | return report, err 18 | } 19 | 20 | query, err := getFiltersQuery(pruneFilters) 21 | if err != nil { 22 | return report, err 23 | } 24 | 25 | serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil) 26 | if err != nil { 27 | return report, err 28 | } 29 | defer ensureReaderClosed(serverResp) 30 | 31 | if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { 32 | return report, fmt.Errorf("Error retrieving disk usage: %v", err) 33 | } 34 | 35 | return report, nil 36 | } 37 | -------------------------------------------------------------------------------- /secret_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "docker.io/go-docker/api/types/swarm" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // SecretList returns the list of secrets. 14 | func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) { 15 | if err := cli.NewVersionError("1.25", "secret list"); err != nil { 16 | return nil, err 17 | } 18 | query := url.Values{} 19 | 20 | if options.Filters.Len() > 0 { 21 | filterJSON, err := filters.ToJSON(options.Filters) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | query.Set("filters", filterJSON) 27 | } 28 | 29 | resp, err := cli.get(ctx, "/secrets", query, nil) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | var secrets []swarm.Secret 35 | err = json.NewDecoder(resp.body).Decode(&secrets) 36 | ensureReaderClosed(resp) 37 | return secrets, err 38 | } 39 | -------------------------------------------------------------------------------- /volume_prune.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // VolumesPrune requests the daemon to delete unused data 13 | func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (types.VolumesPruneReport, error) { 14 | var report types.VolumesPruneReport 15 | 16 | if err := cli.NewVersionError("1.25", "volume prune"); err != nil { 17 | return report, err 18 | } 19 | 20 | query, err := getFiltersQuery(pruneFilters) 21 | if err != nil { 22 | return report, err 23 | } 24 | 25 | serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil) 26 | if err != nil { 27 | return report, err 28 | } 29 | defer ensureReaderClosed(serverResp) 30 | 31 | if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { 32 | return report, fmt.Errorf("Error retrieving volume prune report: %v", err) 33 | } 34 | 35 | return report, nil 36 | } 37 | -------------------------------------------------------------------------------- /container_prune.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // ContainersPrune requests the daemon to delete unused data 13 | func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) { 14 | var report types.ContainersPruneReport 15 | 16 | if err := cli.NewVersionError("1.25", "container prune"); err != nil { 17 | return report, err 18 | } 19 | 20 | query, err := getFiltersQuery(pruneFilters) 21 | if err != nil { 22 | return report, err 23 | } 24 | 25 | serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil) 26 | if err != nil { 27 | return report, err 28 | } 29 | defer ensureReaderClosed(serverResp) 30 | 31 | if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { 32 | return report, fmt.Errorf("Error retrieving disk usage: %v", err) 33 | } 34 | 35 | return report, nil 36 | } 37 | -------------------------------------------------------------------------------- /network_prune.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "golang.org/x/net/context" 10 | ) 11 | 12 | // NetworksPrune requests the daemon to delete unused networks 13 | func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error) { 14 | var report types.NetworksPruneReport 15 | 16 | if err := cli.NewVersionError("1.25", "network prune"); err != nil { 17 | return report, err 18 | } 19 | 20 | query, err := getFiltersQuery(pruneFilters) 21 | if err != nil { 22 | return report, err 23 | } 24 | 25 | serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil) 26 | if err != nil { 27 | return report, err 28 | } 29 | defer ensureReaderClosed(serverResp) 30 | 31 | if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { 32 | return report, fmt.Errorf("Error retrieving network prune report: %v", err) 33 | } 34 | 35 | return report, nil 36 | } 37 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package docker is the official Go client for the Docker API. 3 | 4 | 5 | For more information about the Docker API, see the documentation: 6 | https://docs.docker.com/develop/api 7 | 8 | Usage 9 | 10 | You use the library by creating a client object and calling methods on it. The 11 | client can be created either from environment variables with NewEnvClient, or 12 | configured manually with NewClient. 13 | 14 | For example, to list running containers (the equivalent of "docker ps"): 15 | 16 | package main 17 | 18 | import ( 19 | "context" 20 | "fmt" 21 | 22 | "docker.io/go-docker" 23 | "docker.io/go-docker/api/types" 24 | ) 25 | 26 | func main() { 27 | cli, err := docker.NewEnvClient() 28 | if err != nil { 29 | panic(err) 30 | } 31 | 32 | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) 33 | if err != nil { 34 | panic(err) 35 | } 36 | 37 | for _, container := range containers { 38 | fmt.Printf("%s %s\n", container.ID[:10], container.Image) 39 | } 40 | } 41 | */ 42 | package docker // import "docker.io/go-docker" 43 | -------------------------------------------------------------------------------- /scripts/files/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package docker is the official Go client for the Docker API. 3 | 4 | 5 | For more information about the Docker API, see the documentation: 6 | https://docs.docker.com/develop/api 7 | 8 | Usage 9 | 10 | You use the library by creating a client object and calling methods on it. The 11 | client can be created either from environment variables with NewEnvClient, or 12 | configured manually with NewClient. 13 | 14 | For example, to list running containers (the equivalent of "docker ps"): 15 | 16 | package main 17 | 18 | import ( 19 | "context" 20 | "fmt" 21 | 22 | "docker.io/go-docker" 23 | "docker.io/go-docker/api/types" 24 | ) 25 | 26 | func main() { 27 | cli, err := docker.NewEnvClient() 28 | if err != nil { 29 | panic(err) 30 | } 31 | 32 | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) 33 | if err != nil { 34 | panic(err) 35 | } 36 | 37 | for _, container := range containers { 38 | fmt.Printf("%s %s\n", container.ID[:10], container.Image) 39 | } 40 | } 41 | */ 42 | package docker // import "docker.io/go-docker" 43 | -------------------------------------------------------------------------------- /container_resize.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | "strconv" 6 | 7 | "docker.io/go-docker/api/types" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ContainerResize changes the size of the tty for a container. 12 | func (cli *Client) ContainerResize(ctx context.Context, containerID string, options types.ResizeOptions) error { 13 | return cli.resize(ctx, "/containers/"+containerID, options.Height, options.Width) 14 | } 15 | 16 | // ContainerExecResize changes the size of the tty for an exec process running inside a container. 17 | func (cli *Client) ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error { 18 | return cli.resize(ctx, "/exec/"+execID, options.Height, options.Width) 19 | } 20 | 21 | func (cli *Client) resize(ctx context.Context, basePath string, height, width uint) error { 22 | query := url.Values{} 23 | query.Set("h", strconv.Itoa(int(height))) 24 | query.Set("w", strconv.Itoa(int(width))) 25 | 26 | resp, err := cli.post(ctx, basePath+"/resize", query, nil, nil) 27 | ensureReaderClosed(resp) 28 | return err 29 | } 30 | -------------------------------------------------------------------------------- /service_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/url" 9 | 10 | "docker.io/go-docker/api/types" 11 | "docker.io/go-docker/api/types/swarm" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | // ServiceInspectWithRaw returns the service information and the raw data. 16 | func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, opts types.ServiceInspectOptions) (swarm.Service, []byte, error) { 17 | query := url.Values{} 18 | query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults)) 19 | serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil) 20 | if err != nil { 21 | return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID) 22 | } 23 | defer ensureReaderClosed(serverResp) 24 | 25 | body, err := ioutil.ReadAll(serverResp.body) 26 | if err != nil { 27 | return swarm.Service{}, nil, err 28 | } 29 | 30 | var response swarm.Service 31 | rdr := bytes.NewReader(body) 32 | err = json.NewDecoder(rdr).Decode(&response) 33 | return response, body, err 34 | } 35 | -------------------------------------------------------------------------------- /image_import.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | 7 | "golang.org/x/net/context" 8 | 9 | "github.com/docker/distribution/reference" 10 | "docker.io/go-docker/api/types" 11 | ) 12 | 13 | // ImageImport creates a new image based in the source options. 14 | // It returns the JSON content in the response body. 15 | func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) { 16 | if ref != "" { 17 | //Check if the given image name can be resolved 18 | if _, err := reference.ParseNormalizedNamed(ref); err != nil { 19 | return nil, err 20 | } 21 | } 22 | 23 | query := url.Values{} 24 | query.Set("fromSrc", source.SourceName) 25 | query.Set("repo", ref) 26 | query.Set("tag", options.Tag) 27 | query.Set("message", options.Message) 28 | for _, change := range options.Changes { 29 | query.Add("changes", change) 30 | } 31 | 32 | resp, err := cli.postRaw(ctx, "/images/create", query, source.Source, nil) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return resp.body, nil 37 | } 38 | -------------------------------------------------------------------------------- /api/types/image_summary.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // This file was generated by the swagger tool. 4 | // Editing this file might prove futile when you re-run the swagger generate command 5 | 6 | // ImageSummary image summary 7 | // swagger:model ImageSummary 8 | type ImageSummary struct { 9 | 10 | // containers 11 | // Required: true 12 | Containers int64 `json:"Containers"` 13 | 14 | // created 15 | // Required: true 16 | Created int64 `json:"Created"` 17 | 18 | // Id 19 | // Required: true 20 | ID string `json:"Id"` 21 | 22 | // labels 23 | // Required: true 24 | Labels map[string]string `json:"Labels"` 25 | 26 | // parent Id 27 | // Required: true 28 | ParentID string `json:"ParentId"` 29 | 30 | // repo digests 31 | // Required: true 32 | RepoDigests []string `json:"RepoDigests"` 33 | 34 | // repo tags 35 | // Required: true 36 | RepoTags []string `json:"RepoTags"` 37 | 38 | // shared size 39 | // Required: true 40 | SharedSize int64 `json:"SharedSize"` 41 | 42 | // size 43 | // Required: true 44 | Size int64 `json:"Size"` 45 | 46 | // virtual size 47 | // Required: true 48 | VirtualSize int64 `json:"VirtualSize"` 49 | } 50 | -------------------------------------------------------------------------------- /api/types/versions/v1p19/types.go: -------------------------------------------------------------------------------- 1 | // Package v1p19 provides specific API types for the API version 1, patch 19. 2 | package v1p19 3 | 4 | import ( 5 | "docker.io/go-docker/api/types" 6 | "docker.io/go-docker/api/types/container" 7 | "docker.io/go-docker/api/types/versions/v1p20" 8 | "github.com/docker/go-connections/nat" 9 | ) 10 | 11 | // ContainerJSON is a backcompatibility struct for APIs prior to 1.20. 12 | // Note this is not used by the Windows daemon. 13 | type ContainerJSON struct { 14 | *types.ContainerJSONBase 15 | Volumes map[string]string 16 | VolumesRW map[string]bool 17 | Config *ContainerConfig 18 | NetworkSettings *v1p20.NetworkSettings 19 | } 20 | 21 | // ContainerConfig is a backcompatibility struct for APIs prior to 1.20. 22 | type ContainerConfig struct { 23 | *container.Config 24 | 25 | MacAddress string 26 | NetworkDisabled bool 27 | ExposedPorts map[nat.Port]struct{} 28 | 29 | // backward compatibility, they now live in HostConfig 30 | VolumeDriver string 31 | Memory int64 32 | MemorySwap int64 33 | CPUShares int64 `json:"CpuShares"` 34 | CPUSet string `json:"Cpuset"` 35 | } 36 | -------------------------------------------------------------------------------- /image_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | 7 | "golang.org/x/net/context" 8 | 9 | "github.com/docker/distribution/reference" 10 | "docker.io/go-docker/api/types" 11 | ) 12 | 13 | // ImageCreate creates a new image based in the parent options. 14 | // It returns the JSON content in the response body. 15 | func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) { 16 | ref, err := reference.ParseNormalizedNamed(parentReference) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | query := url.Values{} 22 | query.Set("fromImage", reference.FamiliarName(ref)) 23 | query.Set("tag", getAPITagFromNamedRef(ref)) 24 | resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return resp.body, nil 29 | } 30 | 31 | func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) { 32 | headers := map[string][]string{"X-Registry-Auth": {registryAuth}} 33 | return cli.post(ctx, "/images/create", query, nil, headers) 34 | } 35 | -------------------------------------------------------------------------------- /api/types/container/hostconfig_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package container 4 | 5 | // IsValid indicates if an isolation technology is valid 6 | func (i Isolation) IsValid() bool { 7 | return i.IsDefault() 8 | } 9 | 10 | // NetworkName returns the name of the network stack. 11 | func (n NetworkMode) NetworkName() string { 12 | if n.IsBridge() { 13 | return "bridge" 14 | } else if n.IsHost() { 15 | return "host" 16 | } else if n.IsContainer() { 17 | return "container" 18 | } else if n.IsNone() { 19 | return "none" 20 | } else if n.IsDefault() { 21 | return "default" 22 | } else if n.IsUserDefined() { 23 | return n.UserDefined() 24 | } 25 | return "" 26 | } 27 | 28 | // IsBridge indicates whether container uses the bridge network stack 29 | func (n NetworkMode) IsBridge() bool { 30 | return n == "bridge" 31 | } 32 | 33 | // IsHost indicates whether container uses the host network stack. 34 | func (n NetworkMode) IsHost() bool { 35 | return n == "host" 36 | } 37 | 38 | // IsUserDefined indicates user-created network 39 | func (n NetworkMode) IsUserDefined() bool { 40 | return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() 41 | } 42 | -------------------------------------------------------------------------------- /distribution_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | registrytypes "docker.io/go-docker/api/types/registry" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // DistributionInspect returns the image digest with full Manifest 12 | func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registrytypes.DistributionInspect, error) { 13 | // Contact the registry to retrieve digest and platform information 14 | var distributionInspect registrytypes.DistributionInspect 15 | 16 | if err := cli.NewVersionError("1.30", "distribution inspect"); err != nil { 17 | return distributionInspect, err 18 | } 19 | var headers map[string][]string 20 | 21 | if encodedRegistryAuth != "" { 22 | headers = map[string][]string{ 23 | "X-Registry-Auth": {encodedRegistryAuth}, 24 | } 25 | } 26 | 27 | resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers) 28 | if err != nil { 29 | return distributionInspect, err 30 | } 31 | 32 | err = json.NewDecoder(resp.body).Decode(&distributionInspect) 33 | ensureReaderClosed(resp) 34 | return distributionInspect, err 35 | } 36 | -------------------------------------------------------------------------------- /image_tag.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "github.com/docker/distribution/reference" 7 | "github.com/pkg/errors" 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | // ImageTag tags an image in the docker host 12 | func (cli *Client) ImageTag(ctx context.Context, source, target string) error { 13 | if _, err := reference.ParseAnyReference(source); err != nil { 14 | return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", source) 15 | } 16 | 17 | ref, err := reference.ParseNormalizedNamed(target) 18 | if err != nil { 19 | return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target) 20 | } 21 | 22 | if _, isCanonical := ref.(reference.Canonical); isCanonical { 23 | return errors.New("refusing to create a tag with a digest reference") 24 | } 25 | 26 | ref = reference.TagNameOnly(ref) 27 | 28 | query := url.Values{} 29 | query.Set("repo", reference.FamiliarName(ref)) 30 | if tagged, ok := ref.(reference.Tagged); ok { 31 | query.Set("tag", tagged.Tag()) 32 | } 33 | 34 | resp, err := cli.post(ctx, "/images/"+source+"/tag", query, nil, nil) 35 | ensureReaderClosed(resp) 36 | return err 37 | } 38 | -------------------------------------------------------------------------------- /container_pause_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestContainerPauseError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | err := client.ContainerPause(context.Background(), "nothing") 19 | if err == nil || err.Error() != "Error response from daemon: Server error" { 20 | t.Fatalf("expected a Server Error, got %v", err) 21 | } 22 | } 23 | 24 | func TestContainerPause(t *testing.T) { 25 | expectedURL := "/containers/container_id/pause" 26 | client := &Client{ 27 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 28 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 29 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 30 | } 31 | return &http.Response{ 32 | StatusCode: http.StatusOK, 33 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 34 | }, nil 35 | }), 36 | } 37 | err := client.ContainerPause(context.Background(), "container_id") 38 | if err != nil { 39 | t.Fatal(err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /api/types/versions/README.md: -------------------------------------------------------------------------------- 1 | # Legacy API type versions 2 | 3 | This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`. 4 | 5 | Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`. 6 | 7 | ## Package name conventions 8 | 9 | The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention: 10 | 11 | 1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`. 12 | 2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`. 13 | 14 | For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`. 15 | -------------------------------------------------------------------------------- /container_unpause_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestContainerUnpauseError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | err := client.ContainerUnpause(context.Background(), "nothing") 19 | if err == nil || err.Error() != "Error response from daemon: Server error" { 20 | t.Fatalf("expected a Server Error, got %v", err) 21 | } 22 | } 23 | 24 | func TestContainerUnpause(t *testing.T) { 25 | expectedURL := "/containers/container_id/unpause" 26 | client := &Client{ 27 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 28 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 29 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 30 | } 31 | return &http.Response{ 32 | StatusCode: http.StatusOK, 33 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 34 | }, nil 35 | }), 36 | } 37 | err := client.ContainerUnpause(context.Background(), "container_id") 38 | if err != nil { 39 | t.Fatal(err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /api/types/versions/v1p20/types.go: -------------------------------------------------------------------------------- 1 | // Package v1p20 provides specific API types for the API version 1, patch 20. 2 | package v1p20 3 | 4 | import ( 5 | "docker.io/go-docker/api/types" 6 | "docker.io/go-docker/api/types/container" 7 | "github.com/docker/go-connections/nat" 8 | ) 9 | 10 | // ContainerJSON is a backcompatibility struct for the API 1.20 11 | type ContainerJSON struct { 12 | *types.ContainerJSONBase 13 | Mounts []types.MountPoint 14 | Config *ContainerConfig 15 | NetworkSettings *NetworkSettings 16 | } 17 | 18 | // ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20 19 | type ContainerConfig struct { 20 | *container.Config 21 | 22 | MacAddress string 23 | NetworkDisabled bool 24 | ExposedPorts map[nat.Port]struct{} 25 | 26 | // backward compatibility, they now live in HostConfig 27 | VolumeDriver string 28 | } 29 | 30 | // StatsJSON is a backcompatibility struct used in Stats for APIs prior to 1.21 31 | type StatsJSON struct { 32 | types.Stats 33 | Network types.NetworkStats `json:"network,omitempty"` 34 | } 35 | 36 | // NetworkSettings is a backward compatible struct for APIs prior to 1.21 37 | type NetworkSettings struct { 38 | types.NetworkSettingsBase 39 | types.DefaultNetworkSettings 40 | } 41 | -------------------------------------------------------------------------------- /task_logs.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | "time" 7 | 8 | "golang.org/x/net/context" 9 | 10 | "docker.io/go-docker/api/types" 11 | timetypes "docker.io/go-docker/api/types/time" 12 | ) 13 | 14 | // TaskLogs returns the logs generated by a task in an io.ReadCloser. 15 | // It's up to the caller to close the stream. 16 | func (cli *Client) TaskLogs(ctx context.Context, taskID string, options types.ContainerLogsOptions) (io.ReadCloser, error) { 17 | query := url.Values{} 18 | if options.ShowStdout { 19 | query.Set("stdout", "1") 20 | } 21 | 22 | if options.ShowStderr { 23 | query.Set("stderr", "1") 24 | } 25 | 26 | if options.Since != "" { 27 | ts, err := timetypes.GetTimestamp(options.Since, time.Now()) 28 | if err != nil { 29 | return nil, err 30 | } 31 | query.Set("since", ts) 32 | } 33 | 34 | if options.Timestamps { 35 | query.Set("timestamps", "1") 36 | } 37 | 38 | if options.Details { 39 | query.Set("details", "1") 40 | } 41 | 42 | if options.Follow { 43 | query.Set("follow", "1") 44 | } 45 | query.Set("tail", options.Tail) 46 | 47 | resp, err := cli.get(ctx, "/tasks/"+taskID+"/logs", query, nil) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return resp.body, nil 52 | } 53 | -------------------------------------------------------------------------------- /service_logs.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | "time" 7 | 8 | "golang.org/x/net/context" 9 | 10 | "docker.io/go-docker/api/types" 11 | timetypes "docker.io/go-docker/api/types/time" 12 | ) 13 | 14 | // ServiceLogs returns the logs generated by a service in an io.ReadCloser. 15 | // It's up to the caller to close the stream. 16 | func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options types.ContainerLogsOptions) (io.ReadCloser, error) { 17 | query := url.Values{} 18 | if options.ShowStdout { 19 | query.Set("stdout", "1") 20 | } 21 | 22 | if options.ShowStderr { 23 | query.Set("stderr", "1") 24 | } 25 | 26 | if options.Since != "" { 27 | ts, err := timetypes.GetTimestamp(options.Since, time.Now()) 28 | if err != nil { 29 | return nil, err 30 | } 31 | query.Set("since", ts) 32 | } 33 | 34 | if options.Timestamps { 35 | query.Set("timestamps", "1") 36 | } 37 | 38 | if options.Details { 39 | query.Set("details", "1") 40 | } 41 | 42 | if options.Follow { 43 | query.Set("follow", "1") 44 | } 45 | query.Set("tail", options.Tail) 46 | 47 | resp, err := cli.get(ctx, "/services/"+serviceID+"/logs", query, nil) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return resp.body, nil 52 | } 53 | -------------------------------------------------------------------------------- /api/types/swarm/common.go: -------------------------------------------------------------------------------- 1 | package swarm 2 | 3 | import "time" 4 | 5 | // Version represents the internal object version. 6 | type Version struct { 7 | Index uint64 `json:",omitempty"` 8 | } 9 | 10 | // Meta is a base object inherited by most of the other once. 11 | type Meta struct { 12 | Version Version `json:",omitempty"` 13 | CreatedAt time.Time `json:",omitempty"` 14 | UpdatedAt time.Time `json:",omitempty"` 15 | } 16 | 17 | // Annotations represents how to describe an object. 18 | type Annotations struct { 19 | Name string `json:",omitempty"` 20 | Labels map[string]string `json:"Labels"` 21 | } 22 | 23 | // Driver represents a driver (network, logging, secrets backend). 24 | type Driver struct { 25 | Name string `json:",omitempty"` 26 | Options map[string]string `json:",omitempty"` 27 | } 28 | 29 | // TLSInfo represents the TLS information about what CA certificate is trusted, 30 | // and who the issuer for a TLS certificate is 31 | type TLSInfo struct { 32 | // TrustRoot is the trusted CA root certificate in PEM format 33 | TrustRoot string `json:",omitempty"` 34 | 35 | // CertIssuer is the raw subject bytes of the issuer 36 | CertIssuerSubject []byte `json:",omitempty"` 37 | 38 | // CertIssuerPublicKey is the raw public key bytes of the issuer 39 | CertIssuerPublicKey []byte `json:",omitempty"` 40 | } 41 | -------------------------------------------------------------------------------- /network_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestNetworkRemoveError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | 19 | err := client.NetworkRemove(context.Background(), "network_id") 20 | if err == nil || err.Error() != "Error response from daemon: Server error" { 21 | t.Fatalf("expected a Server Error, got %v", err) 22 | } 23 | } 24 | 25 | func TestNetworkRemove(t *testing.T) { 26 | expectedURL := "/networks/network_id" 27 | 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | if req.Method != "DELETE" { 34 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 35 | } 36 | return &http.Response{ 37 | StatusCode: http.StatusOK, 38 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 39 | }, nil 40 | }), 41 | } 42 | 43 | err := client.NetworkRemove(context.Background(), "network_id") 44 | if err != nil { 45 | t.Fatal(err) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /plugin_set_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestPluginSetError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | 19 | err := client.PluginSet(context.Background(), "plugin_name", []string{}) 20 | if err == nil || err.Error() != "Error response from daemon: Server error" { 21 | t.Fatalf("expected a Server Error, got %v", err) 22 | } 23 | } 24 | 25 | func TestPluginSet(t *testing.T) { 26 | expectedURL := "/plugins/plugin_name/set" 27 | 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | if req.Method != "POST" { 34 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 35 | } 36 | return &http.Response{ 37 | StatusCode: http.StatusOK, 38 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 39 | }, nil 40 | }), 41 | } 42 | 43 | err := client.PluginSet(context.Background(), "plugin_name", []string{"arg1"}) 44 | if err != nil { 45 | t.Fatal(err) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /volume_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestVolumeRemoveError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | 19 | err := client.VolumeRemove(context.Background(), "volume_id", false) 20 | if err == nil || err.Error() != "Error response from daemon: Server error" { 21 | t.Fatalf("expected a Server Error, got %v", err) 22 | } 23 | } 24 | 25 | func TestVolumeRemove(t *testing.T) { 26 | expectedURL := "/volumes/volume_id" 27 | 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | if req.Method != "DELETE" { 34 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 35 | } 36 | return &http.Response{ 37 | StatusCode: http.StatusOK, 38 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 39 | }, nil 40 | }), 41 | } 42 | 43 | err := client.VolumeRemove(context.Background(), "volume_id", false) 44 | if err != nil { 45 | t.Fatal(err) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /container_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | "strconv" 7 | 8 | "docker.io/go-docker/api/types" 9 | "docker.io/go-docker/api/types/filters" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // ContainerList returns the list of containers in the docker host. 14 | func (cli *Client) ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) { 15 | query := url.Values{} 16 | 17 | if options.All { 18 | query.Set("all", "1") 19 | } 20 | 21 | if options.Limit != -1 { 22 | query.Set("limit", strconv.Itoa(options.Limit)) 23 | } 24 | 25 | if options.Since != "" { 26 | query.Set("since", options.Since) 27 | } 28 | 29 | if options.Before != "" { 30 | query.Set("before", options.Before) 31 | } 32 | 33 | if options.Size { 34 | query.Set("size", "1") 35 | } 36 | 37 | if options.Filters.Len() > 0 { 38 | filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters) 39 | 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | query.Set("filters", filterJSON) 45 | } 46 | 47 | resp, err := cli.get(ctx, "/containers/json", query, nil) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | var containers []types.Container 53 | err = json.NewDecoder(resp.body).Decode(&containers) 54 | ensureReaderClosed(resp) 55 | return containers, err 56 | } 57 | -------------------------------------------------------------------------------- /image_list.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | 7 | "docker.io/go-docker/api/types" 8 | "docker.io/go-docker/api/types/filters" 9 | "docker.io/go-docker/api/types/versions" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // ImageList returns a list of images in the docker host. 14 | func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions) ([]types.ImageSummary, error) { 15 | var images []types.ImageSummary 16 | query := url.Values{} 17 | 18 | optionFilters := options.Filters 19 | referenceFilters := optionFilters.Get("reference") 20 | if versions.LessThan(cli.version, "1.25") && len(referenceFilters) > 0 { 21 | query.Set("filter", referenceFilters[0]) 22 | for _, filterValue := range referenceFilters { 23 | optionFilters.Del("reference", filterValue) 24 | } 25 | } 26 | if optionFilters.Len() > 0 { 27 | filterJSON, err := filters.ToParamWithVersion(cli.version, optionFilters) 28 | if err != nil { 29 | return images, err 30 | } 31 | query.Set("filters", filterJSON) 32 | } 33 | if options.All { 34 | query.Set("all", "1") 35 | } 36 | 37 | serverResp, err := cli.get(ctx, "/images/json", query, nil) 38 | if err != nil { 39 | return images, err 40 | } 41 | 42 | err = json.NewDecoder(serverResp.body).Decode(&images) 43 | ensureReaderClosed(serverResp) 44 | return images, err 45 | } 46 | -------------------------------------------------------------------------------- /plugin_upgrade.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | 7 | "github.com/docker/distribution/reference" 8 | "docker.io/go-docker/api/types" 9 | "github.com/pkg/errors" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // PluginUpgrade upgrades a plugin 14 | func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) { 15 | if err := cli.NewVersionError("1.26", "plugin upgrade"); err != nil { 16 | return nil, err 17 | } 18 | query := url.Values{} 19 | if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil { 20 | return nil, errors.Wrap(err, "invalid remote reference") 21 | } 22 | query.Set("remote", options.RemoteRef) 23 | 24 | privileges, err := cli.checkPluginPermissions(ctx, query, options) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | resp, err := cli.tryPluginUpgrade(ctx, query, privileges, name, options.RegistryAuth) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return resp.body, nil 34 | } 35 | 36 | func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) { 37 | headers := map[string][]string{"X-Registry-Auth": {registryAuth}} 38 | return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, headers) 39 | } 40 | -------------------------------------------------------------------------------- /swarm_join_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | 13 | "docker.io/go-docker/api/types/swarm" 14 | ) 15 | 16 | func TestSwarmJoinError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.SwarmJoin(context.Background(), swarm.JoinRequest{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestSwarmJoin(t *testing.T) { 28 | expectedURL := "/swarm/join" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | if req.Method != "POST" { 36 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 37 | } 38 | return &http.Response{ 39 | StatusCode: http.StatusOK, 40 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 41 | }, nil 42 | }), 43 | } 44 | 45 | err := client.SwarmJoin(context.Background(), swarm.JoinRequest{ 46 | ListenAddr: "0.0.0.0:2377", 47 | }) 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /container_kill_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestContainerKillError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | err := client.ContainerKill(context.Background(), "nothing", "SIGKILL") 19 | if err == nil || err.Error() != "Error response from daemon: Server error" { 20 | t.Fatalf("expected a Server Error, got %v", err) 21 | } 22 | } 23 | 24 | func TestContainerKill(t *testing.T) { 25 | expectedURL := "/containers/container_id/kill" 26 | client := &Client{ 27 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 28 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 29 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 30 | } 31 | signal := req.URL.Query().Get("signal") 32 | if signal != "SIGKILL" { 33 | return nil, fmt.Errorf("signal not set in URL query properly. Expected 'SIGKILL', got %s", signal) 34 | } 35 | return &http.Response{ 36 | StatusCode: http.StatusOK, 37 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 38 | }, nil 39 | }), 40 | } 41 | 42 | err := client.ContainerKill(context.Background(), "container_id", "SIGKILL") 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /container_rename_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestContainerRenameError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | err := client.ContainerRename(context.Background(), "nothing", "newNothing") 19 | if err == nil || err.Error() != "Error response from daemon: Server error" { 20 | t.Fatalf("expected a Server Error, got %v", err) 21 | } 22 | } 23 | 24 | func TestContainerRename(t *testing.T) { 25 | expectedURL := "/containers/container_id/rename" 26 | client := &Client{ 27 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 28 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 29 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 30 | } 31 | name := req.URL.Query().Get("name") 32 | if name != "newName" { 33 | return nil, fmt.Errorf("name not set in URL query properly. Expected 'newName', got %s", name) 34 | } 35 | return &http.Response{ 36 | StatusCode: http.StatusOK, 37 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 38 | }, nil 39 | }), 40 | } 41 | 42 | err := client.ContainerRename(context.Background(), "container_id", "newName") 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /plugin_enable_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestPluginEnableError(t *testing.T) { 16 | client := &Client{ 17 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 18 | } 19 | 20 | err := client.PluginEnable(context.Background(), "plugin_name", types.PluginEnableOptions{}) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | } 25 | 26 | func TestPluginEnable(t *testing.T) { 27 | expectedURL := "/plugins/plugin_name/enable" 28 | 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | if req.Method != "POST" { 35 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 36 | } 37 | return &http.Response{ 38 | StatusCode: http.StatusOK, 39 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 40 | }, nil 41 | }), 42 | } 43 | 44 | err := client.PluginEnable(context.Background(), "plugin_name", types.PluginEnableOptions{}) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /node_update_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | 13 | "docker.io/go-docker/api/types/swarm" 14 | ) 15 | 16 | func TestNodeUpdateError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.NodeUpdate(context.Background(), "node_id", swarm.Version{}, swarm.NodeSpec{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestNodeUpdate(t *testing.T) { 28 | expectedURL := "/nodes/node_id/update" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | if req.Method != "POST" { 36 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 37 | } 38 | return &http.Response{ 39 | StatusCode: http.StatusOK, 40 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 41 | }, nil 42 | }), 43 | } 44 | 45 | err := client.NodeUpdate(context.Background(), "node_id", swarm.Version{}, swarm.NodeSpec{}) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /plugin_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types" 12 | 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestPluginRemoveError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.PluginRemove(context.Background(), "plugin_name", types.PluginRemoveOptions{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestPluginRemove(t *testing.T) { 28 | expectedURL := "/plugins/plugin_name" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | if req.Method != "DELETE" { 36 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 37 | } 38 | return &http.Response{ 39 | StatusCode: http.StatusOK, 40 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 41 | }, nil 42 | }), 43 | } 44 | 45 | err := client.PluginRemove(context.Background(), "plugin_name", types.PluginRemoveOptions{}) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tlsconfig_clone_go17.go: -------------------------------------------------------------------------------- 1 | // +build go1.7,!go1.8 2 | 3 | package docker // import "docker.io/go-docker" 4 | 5 | import "crypto/tls" 6 | 7 | // tlsConfigClone returns a clone of tls.Config. This function is provided for 8 | // compatibility for go1.7 that doesn't include this method in stdlib. 9 | func tlsConfigClone(c *tls.Config) *tls.Config { 10 | return &tls.Config{ 11 | Rand: c.Rand, 12 | Time: c.Time, 13 | Certificates: c.Certificates, 14 | NameToCertificate: c.NameToCertificate, 15 | GetCertificate: c.GetCertificate, 16 | RootCAs: c.RootCAs, 17 | NextProtos: c.NextProtos, 18 | ServerName: c.ServerName, 19 | ClientAuth: c.ClientAuth, 20 | ClientCAs: c.ClientCAs, 21 | InsecureSkipVerify: c.InsecureSkipVerify, 22 | CipherSuites: c.CipherSuites, 23 | PreferServerCipherSuites: c.PreferServerCipherSuites, 24 | SessionTicketsDisabled: c.SessionTicketsDisabled, 25 | SessionTicketKey: c.SessionTicketKey, 26 | ClientSessionCache: c.ClientSessionCache, 27 | MinVersion: c.MinVersion, 28 | MaxVersion: c.MaxVersion, 29 | CurvePreferences: c.CurvePreferences, 30 | DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, 31 | Renegotiation: c.Renegotiation, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /plugin_disable_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestPluginDisableError(t *testing.T) { 16 | client := &Client{ 17 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 18 | } 19 | 20 | err := client.PluginDisable(context.Background(), "plugin_name", types.PluginDisableOptions{}) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | } 25 | 26 | func TestPluginDisable(t *testing.T) { 27 | expectedURL := "/plugins/plugin_name/disable" 28 | 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | if req.Method != "POST" { 35 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 36 | } 37 | return &http.Response{ 38 | StatusCode: http.StatusOK, 39 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 40 | }, nil 41 | }), 42 | } 43 | 44 | err := client.PluginDisable(context.Background(), "plugin_name", types.PluginDisableOptions{}) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /swarm_update_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | 13 | "docker.io/go-docker/api/types/swarm" 14 | ) 15 | 16 | func TestSwarmUpdateError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.SwarmUpdate(context.Background(), swarm.Version{}, swarm.Spec{}, swarm.UpdateFlags{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestSwarmUpdate(t *testing.T) { 28 | expectedURL := "/swarm/update" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | if req.Method != "POST" { 36 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 37 | } 38 | return &http.Response{ 39 | StatusCode: http.StatusOK, 40 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 41 | }, nil 42 | }), 43 | } 44 | 45 | err := client.SwarmUpdate(context.Background(), swarm.Version{}, swarm.Spec{}, swarm.UpdateFlags{}) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /disk_usage_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestDiskUsageError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | _, err := client.DiskUsage(context.Background()) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | } 25 | 26 | func TestDiskUsage(t *testing.T) { 27 | expectedURL := "/system/df" 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | 34 | du := types.DiskUsage{ 35 | LayersSize: int64(100), 36 | Images: nil, 37 | Containers: nil, 38 | Volumes: nil, 39 | } 40 | 41 | b, err := json.Marshal(du) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | return &http.Response{ 47 | StatusCode: http.StatusOK, 48 | Body: ioutil.NopCloser(bytes.NewReader(b)), 49 | }, nil 50 | }), 51 | } 52 | if _, err := client.DiskUsage(context.Background()); err != nil { 53 | t.Fatal(err) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /container_stop_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | "time" 11 | 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestContainerStopError(t *testing.T) { 16 | client := &Client{ 17 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 18 | } 19 | timeout := 0 * time.Second 20 | err := client.ContainerStop(context.Background(), "nothing", &timeout) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | } 25 | 26 | func TestContainerStop(t *testing.T) { 27 | expectedURL := "/containers/container_id/stop" 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | t := req.URL.Query().Get("t") 34 | if t != "100" { 35 | return nil, fmt.Errorf("t (timeout) not set in URL query properly. Expected '100', got %s", t) 36 | } 37 | return &http.Response{ 38 | StatusCode: http.StatusOK, 39 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 40 | }, nil 41 | }), 42 | } 43 | timeout := 100 * time.Second 44 | err := client.ContainerStop(context.Background(), "container_id", &timeout) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /container_export_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestContainerExportError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | _, err := client.ContainerExport(context.Background(), "nothing") 19 | if err == nil || err.Error() != "Error response from daemon: Server error" { 20 | t.Fatalf("expected a Server Error, got %v", err) 21 | } 22 | } 23 | 24 | func TestContainerExport(t *testing.T) { 25 | expectedURL := "/containers/container_id/export" 26 | client := &Client{ 27 | client: newMockClient(func(r *http.Request) (*http.Response, error) { 28 | if !strings.HasPrefix(r.URL.Path, expectedURL) { 29 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL) 30 | } 31 | 32 | return &http.Response{ 33 | StatusCode: http.StatusOK, 34 | Body: ioutil.NopCloser(bytes.NewReader([]byte("response"))), 35 | }, nil 36 | }), 37 | } 38 | body, err := client.ContainerExport(context.Background(), "container_id") 39 | if err != nil { 40 | t.Fatal(err) 41 | } 42 | defer body.Close() 43 | content, err := ioutil.ReadAll(body) 44 | if err != nil { 45 | t.Fatal(err) 46 | } 47 | if string(content) != "response" { 48 | t.Fatalf("expected response to contain 'response', got %s", string(content)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /swarm_unlock_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | 13 | "docker.io/go-docker/api/types/swarm" 14 | ) 15 | 16 | func TestSwarmUnlockError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.SwarmUnlock(context.Background(), swarm.UnlockRequest{"SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestSwarmUnlock(t *testing.T) { 28 | expectedURL := "/swarm/unlock" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | if req.Method != "POST" { 36 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 37 | } 38 | return &http.Response{ 39 | StatusCode: http.StatusOK, 40 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 41 | }, nil 42 | }), 43 | } 44 | 45 | err := client.SwarmUnlock(context.Background(), swarm.UnlockRequest{"SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"}) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /volume_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | "path" 8 | 9 | "docker.io/go-docker/api/types" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // VolumeInspect returns the information about a specific volume in the docker host. 14 | func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error) { 15 | volume, _, err := cli.VolumeInspectWithRaw(ctx, volumeID) 16 | return volume, err 17 | } 18 | 19 | // VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation 20 | func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) { 21 | // The empty ID needs to be handled here because with an empty ID the 22 | // request url will not contain a trailing / which calls the volume list API 23 | // instead of volume inspect 24 | if volumeID == "" { 25 | return types.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID} 26 | } 27 | 28 | var volume types.Volume 29 | resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil) 30 | if err != nil { 31 | return volume, nil, wrapResponseError(err, resp, "volume", volumeID) 32 | } 33 | defer ensureReaderClosed(resp) 34 | 35 | body, err := ioutil.ReadAll(resp.body) 36 | if err != nil { 37 | return volume, nil, err 38 | } 39 | rdr := bytes.NewReader(body) 40 | err = json.NewDecoder(rdr).Decode(&volume) 41 | return volume, body, err 42 | } 43 | -------------------------------------------------------------------------------- /container_restart_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | "time" 11 | 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestContainerRestartError(t *testing.T) { 16 | client := &Client{ 17 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 18 | } 19 | timeout := 0 * time.Second 20 | err := client.ContainerRestart(context.Background(), "nothing", &timeout) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | } 25 | 26 | func TestContainerRestart(t *testing.T) { 27 | expectedURL := "/containers/container_id/restart" 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | t := req.URL.Query().Get("t") 34 | if t != "100" { 35 | return nil, fmt.Errorf("t (timeout) not set in URL query properly. Expected '100', got %s", t) 36 | } 37 | return &http.Response{ 38 | StatusCode: http.StatusOK, 39 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 40 | }, nil 41 | }), 42 | } 43 | timeout := 100 * time.Second 44 | err := client.ContainerRestart(context.Background(), "container_id", &timeout) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /swarm_init_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | 13 | "docker.io/go-docker/api/types/swarm" 14 | ) 15 | 16 | func TestSwarmInitError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | _, err := client.SwarmInit(context.Background(), swarm.InitRequest{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestSwarmInit(t *testing.T) { 28 | expectedURL := "/swarm/init" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | if req.Method != "POST" { 36 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 37 | } 38 | return &http.Response{ 39 | StatusCode: http.StatusOK, 40 | Body: ioutil.NopCloser(bytes.NewReader([]byte(`"body"`))), 41 | }, nil 42 | }), 43 | } 44 | 45 | resp, err := client.SwarmInit(context.Background(), swarm.InitRequest{ 46 | ListenAddr: "0.0.0.0:2377", 47 | }) 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | if resp != "body" { 52 | t.Fatalf("Expected 'body', got %s", resp) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /plugin_push_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestPluginPushError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | 19 | _, err := client.PluginPush(context.Background(), "plugin_name", "") 20 | if err == nil || err.Error() != "Error response from daemon: Server error" { 21 | t.Fatalf("expected a Server Error, got %v", err) 22 | } 23 | } 24 | 25 | func TestPluginPush(t *testing.T) { 26 | expectedURL := "/plugins/plugin_name" 27 | 28 | client := &Client{ 29 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 32 | } 33 | if req.Method != "POST" { 34 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 35 | } 36 | auth := req.Header.Get("X-Registry-Auth") 37 | if auth != "authtoken" { 38 | return nil, fmt.Errorf("Invalid auth header : expected 'authtoken', got %s", auth) 39 | } 40 | return &http.Response{ 41 | StatusCode: http.StatusOK, 42 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 43 | }, nil 44 | }), 45 | } 46 | 47 | _, err := client.PluginPush(context.Background(), "plugin_name", "authtoken") 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /task_inspect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types/swarm" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestTaskInspectError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | _, _, err := client.TaskInspectWithRaw(context.Background(), "nothing") 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestTaskInspect(t *testing.T) { 28 | expectedURL := "/tasks/task_id" 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | content, err := json.Marshal(swarm.Task{ 35 | ID: "task_id", 36 | }) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return &http.Response{ 41 | StatusCode: http.StatusOK, 42 | Body: ioutil.NopCloser(bytes.NewReader(content)), 43 | }, nil 44 | }), 45 | } 46 | 47 | taskInspect, _, err := client.TaskInspectWithRaw(context.Background(), "task_id") 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | if taskInspect.ID != "task_id" { 52 | t.Fatalf("expected `task_id`, got %s", taskInspect.ID) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /swarm_inspect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types/swarm" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestSwarmInspectError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | _, err := client.SwarmInspect(context.Background()) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestSwarmInspect(t *testing.T) { 28 | expectedURL := "/swarm" 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | content, err := json.Marshal(swarm.Swarm{ 35 | ClusterInfo: swarm.ClusterInfo{ 36 | ID: "swarm_id", 37 | }, 38 | }) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return &http.Response{ 43 | StatusCode: http.StatusOK, 44 | Body: ioutil.NopCloser(bytes.NewReader(content)), 45 | }, nil 46 | }), 47 | } 48 | 49 | swarmInspect, err := client.SwarmInspect(context.Background()) 50 | if err != nil { 51 | t.Fatal(err) 52 | } 53 | if swarmInspect.ID != "swarm_id" { 54 | t.Fatalf("expected `swarm_id`, got %s", swarmInspect.ID) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /plugin_inspect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestPluginInspectError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | _, _, err := client.PluginInspectWithRaw(context.Background(), "nothing") 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestPluginInspect(t *testing.T) { 28 | expectedURL := "/plugins/plugin_name" 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | content, err := json.Marshal(types.Plugin{ 35 | ID: "plugin_id", 36 | }) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return &http.Response{ 41 | StatusCode: http.StatusOK, 42 | Body: ioutil.NopCloser(bytes.NewReader(content)), 43 | }, nil 44 | }), 45 | } 46 | 47 | pluginInspect, _, err := client.PluginInspectWithRaw(context.Background(), "plugin_name") 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | if pluginInspect.ID != "plugin_id" { 52 | t.Fatalf("expected `plugin_id`, got %s", pluginInspect.ID) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /api/types/container/hostconfig_windows.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // IsBridge indicates whether container uses the bridge network stack 8 | // in windows it is given the name NAT 9 | func (n NetworkMode) IsBridge() bool { 10 | return n == "nat" 11 | } 12 | 13 | // IsHost indicates whether container uses the host network stack. 14 | // returns false as this is not supported by windows 15 | func (n NetworkMode) IsHost() bool { 16 | return false 17 | } 18 | 19 | // IsUserDefined indicates user-created network 20 | func (n NetworkMode) IsUserDefined() bool { 21 | return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() 22 | } 23 | 24 | // IsHyperV indicates the use of a Hyper-V partition for isolation 25 | func (i Isolation) IsHyperV() bool { 26 | return strings.ToLower(string(i)) == "hyperv" 27 | } 28 | 29 | // IsProcess indicates the use of process isolation 30 | func (i Isolation) IsProcess() bool { 31 | return strings.ToLower(string(i)) == "process" 32 | } 33 | 34 | // IsValid indicates if an isolation technology is valid 35 | func (i Isolation) IsValid() bool { 36 | return i.IsDefault() || i.IsHyperV() || i.IsProcess() 37 | } 38 | 39 | // NetworkName returns the name of the network stack. 40 | func (n NetworkMode) NetworkName() string { 41 | if n.IsDefault() { 42 | return "default" 43 | } else if n.IsBridge() { 44 | return "nat" 45 | } else if n.IsNone() { 46 | return "none" 47 | } else if n.IsContainer() { 48 | return "container" 49 | } else if n.IsUserDefined() { 50 | return n.UserDefined() 51 | } 52 | 53 | return "" 54 | } 55 | -------------------------------------------------------------------------------- /api/types/versions/compare.go: -------------------------------------------------------------------------------- 1 | package versions 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | // compare compares two version strings 9 | // returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. 10 | func compare(v1, v2 string) int { 11 | var ( 12 | currTab = strings.Split(v1, ".") 13 | otherTab = strings.Split(v2, ".") 14 | ) 15 | 16 | max := len(currTab) 17 | if len(otherTab) > max { 18 | max = len(otherTab) 19 | } 20 | for i := 0; i < max; i++ { 21 | var currInt, otherInt int 22 | 23 | if len(currTab) > i { 24 | currInt, _ = strconv.Atoi(currTab[i]) 25 | } 26 | if len(otherTab) > i { 27 | otherInt, _ = strconv.Atoi(otherTab[i]) 28 | } 29 | if currInt > otherInt { 30 | return 1 31 | } 32 | if otherInt > currInt { 33 | return -1 34 | } 35 | } 36 | return 0 37 | } 38 | 39 | // LessThan checks if a version is less than another 40 | func LessThan(v, other string) bool { 41 | return compare(v, other) == -1 42 | } 43 | 44 | // LessThanOrEqualTo checks if a version is less than or equal to another 45 | func LessThanOrEqualTo(v, other string) bool { 46 | return compare(v, other) <= 0 47 | } 48 | 49 | // GreaterThan checks if a version is greater than another 50 | func GreaterThan(v, other string) bool { 51 | return compare(v, other) == 1 52 | } 53 | 54 | // GreaterThanOrEqualTo checks if a version is greater than or equal to another 55 | func GreaterThanOrEqualTo(v, other string) bool { 56 | return compare(v, other) >= 0 57 | } 58 | 59 | // Equal checks if a version is equal to another 60 | func Equal(v, other string) bool { 61 | return compare(v, other) == 0 62 | } 63 | -------------------------------------------------------------------------------- /checkpoint_delete_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestCheckpointDeleteError(t *testing.T) { 16 | client := &Client{ 17 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 18 | } 19 | 20 | err := client.CheckpointDelete(context.Background(), "container_id", types.CheckpointDeleteOptions{ 21 | CheckpointID: "checkpoint_id", 22 | }) 23 | 24 | if err == nil || err.Error() != "Error response from daemon: Server error" { 25 | t.Fatalf("expected a Server Error, got %v", err) 26 | } 27 | } 28 | 29 | func TestCheckpointDelete(t *testing.T) { 30 | expectedURL := "/containers/container_id/checkpoints/checkpoint_id" 31 | 32 | client := &Client{ 33 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 34 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 35 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 36 | } 37 | if req.Method != "DELETE" { 38 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 39 | } 40 | return &http.Response{ 41 | StatusCode: http.StatusOK, 42 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 43 | }, nil 44 | }), 45 | } 46 | 47 | err := client.CheckpointDelete(context.Background(), "container_id", types.CheckpointDeleteOptions{ 48 | CheckpointID: "checkpoint_id", 49 | }) 50 | 51 | if err != nil { 52 | t.Fatal(err) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /client_mock_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | "net/http" 8 | 9 | "docker.io/go-docker/api/types" 10 | ) 11 | 12 | // transportFunc allows us to inject a mock transport for testing. We define it 13 | // here so we can detect the tlsconfig and return nil for only this type. 14 | type transportFunc func(*http.Request) (*http.Response, error) 15 | 16 | func (tf transportFunc) RoundTrip(req *http.Request) (*http.Response, error) { 17 | return tf(req) 18 | } 19 | 20 | func newMockClient(doer func(*http.Request) (*http.Response, error)) *http.Client { 21 | return &http.Client{ 22 | Transport: transportFunc(doer), 23 | } 24 | } 25 | 26 | func errorMock(statusCode int, message string) func(req *http.Request) (*http.Response, error) { 27 | return func(req *http.Request) (*http.Response, error) { 28 | header := http.Header{} 29 | header.Set("Content-Type", "application/json") 30 | 31 | body, err := json.Marshal(&types.ErrorResponse{ 32 | Message: message, 33 | }) 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | return &http.Response{ 39 | StatusCode: statusCode, 40 | Body: ioutil.NopCloser(bytes.NewReader(body)), 41 | Header: header, 42 | }, nil 43 | } 44 | } 45 | 46 | func plainTextErrorMock(statusCode int, message string) func(req *http.Request) (*http.Response, error) { 47 | return func(req *http.Request) (*http.Response, error) { 48 | return &http.Response{ 49 | StatusCode: statusCode, 50 | Body: ioutil.NopCloser(bytes.NewReader([]byte(message))), 51 | }, nil 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /scripts/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | ENGINE_BRANCH=master 6 | 7 | domain=docker.io 8 | urlpath=go-docker 9 | importpath="$domain/$urlpath" 10 | package=docker 11 | 12 | sed=$(which gsed) || sed=$(which sed) 13 | dir=$(pwd) 14 | rm -rf *.go api 15 | tmp=${1:-/tmp/go-docker.tmp} 16 | 17 | set -x 18 | cd "$tmp" 19 | 20 | [ ! -d docker ] && git clone --depth 1 -b "$ENGINE_BRANCH" https://github.com/docker/docker 21 | 22 | pushd docker 23 | for folder in api client; do 24 | find "$folder" -name '*.go' -type f -exec sed -i'' -E 's#github.com/docker/docker/api(/?)#'"${importpath}"'/api\1#g' {} \; 25 | find "$folder" -name '*.go' -type f -exec sed -i'' -E 's#github.com/docker/docker/client(/?)#'"${importpath}"'\1#g' {} \; 26 | done 27 | cp client/*.go "$dir/" 28 | cp -rf api "$dir/" 29 | rm -rf \ 30 | "$dir/api/server" \ 31 | "$dir/swarm_get_unlock_key_test.go" \ 32 | "$dir/api/errdefs" \ 33 | "$dir/api/templates" \ 34 | "$dir/api/types/backend" \ 35 | "$dir/api/swagger*" 36 | popd 37 | 38 | pushd "$dir" 39 | find . -name '*.go' -depth 1 -print | xargs $sed -i'' -E 's,^package client\b,package '"${package}"' // import "'${importpath}'",g' 40 | find . -name '*.go' -depth 1 -print | xargs $sed -i'' -E 's,^Package client\b,Package '"${package}"',g' 41 | sed -i'' -E 's#client(\.NewEnvClient\(\))#docker\1#g' client.go 42 | popd 43 | 44 | cd "$dir" 45 | # reset README.md 46 | git checkout README.md 47 | 48 | function strip_doc() { 49 | tail -n +$(grep -n '^package ' "$1" | cut -d: -f1) "$1" > "$1".new 50 | mv "$1".new "$1" 51 | } 52 | 53 | # replace documentation 54 | strip_doc client.go 55 | cp scripts/files/*.go . 56 | -------------------------------------------------------------------------------- /container_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | "net/url" 8 | 9 | "docker.io/go-docker/api/types" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // ContainerInspect returns the container information. 14 | func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) { 15 | serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil) 16 | if err != nil { 17 | return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID) 18 | } 19 | 20 | var response types.ContainerJSON 21 | err = json.NewDecoder(serverResp.body).Decode(&response) 22 | ensureReaderClosed(serverResp) 23 | return response, err 24 | } 25 | 26 | // ContainerInspectWithRaw returns the container information and its raw representation. 27 | func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) { 28 | query := url.Values{} 29 | if getSize { 30 | query.Set("size", "1") 31 | } 32 | serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil) 33 | if err != nil { 34 | return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID) 35 | } 36 | defer ensureReaderClosed(serverResp) 37 | 38 | body, err := ioutil.ReadAll(serverResp.body) 39 | if err != nil { 40 | return types.ContainerJSON{}, nil, err 41 | } 42 | 43 | var response types.ContainerJSON 44 | rdr := bytes.NewReader(body) 45 | err = json.NewDecoder(rdr).Decode(&response) 46 | return response, body, err 47 | } 48 | -------------------------------------------------------------------------------- /network_inspect.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | "net/url" 8 | 9 | "docker.io/go-docker/api/types" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // NetworkInspect returns the information for a specific network configured in the docker host. 14 | func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, error) { 15 | networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options) 16 | return networkResource, err 17 | } 18 | 19 | // NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation. 20 | func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) { 21 | var ( 22 | networkResource types.NetworkResource 23 | resp serverResponse 24 | err error 25 | ) 26 | query := url.Values{} 27 | if options.Verbose { 28 | query.Set("verbose", "true") 29 | } 30 | if options.Scope != "" { 31 | query.Set("scope", options.Scope) 32 | } 33 | resp, err = cli.get(ctx, "/networks/"+networkID, query, nil) 34 | if err != nil { 35 | return networkResource, nil, wrapResponseError(err, resp, "network", networkID) 36 | } 37 | defer ensureReaderClosed(resp) 38 | 39 | body, err := ioutil.ReadAll(resp.body) 40 | if err != nil { 41 | return networkResource, nil, err 42 | } 43 | rdr := bytes.NewReader(body) 44 | err = json.NewDecoder(rdr).Decode(&networkResource) 45 | return networkResource, body, err 46 | } 47 | -------------------------------------------------------------------------------- /container_update_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types/container" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestContainerUpdateError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | _, err := client.ContainerUpdate(context.Background(), "nothing", container.UpdateConfig{}) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | } 25 | 26 | func TestContainerUpdate(t *testing.T) { 27 | expectedURL := "/containers/container_id/update" 28 | 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | 35 | b, err := json.Marshal(container.ContainerUpdateOKBody{}) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | return &http.Response{ 41 | StatusCode: http.StatusOK, 42 | Body: ioutil.NopCloser(bytes.NewReader(b)), 43 | }, nil 44 | }), 45 | } 46 | 47 | _, err := client.ContainerUpdate(context.Background(), "container_id", container.UpdateConfig{ 48 | Resources: container.Resources{ 49 | CPUPeriod: 1, 50 | }, 51 | RestartPolicy: container.RestartPolicy{ 52 | Name: "always", 53 | }, 54 | }) 55 | if err != nil { 56 | t.Fatal(err) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /container_diff_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types/container" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestContainerDiffError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | _, err := client.ContainerDiff(context.Background(), "nothing") 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server Error, got %v", err) 23 | } 24 | 25 | } 26 | 27 | func TestContainerDiff(t *testing.T) { 28 | expectedURL := "/containers/container_id/changes" 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | b, err := json.Marshal([]container.ContainerChangeResponseItem{ 35 | { 36 | Kind: 0, 37 | Path: "/path/1", 38 | }, 39 | { 40 | Kind: 1, 41 | Path: "/path/2", 42 | }, 43 | }) 44 | if err != nil { 45 | return nil, err 46 | } 47 | return &http.Response{ 48 | StatusCode: http.StatusOK, 49 | Body: ioutil.NopCloser(bytes.NewReader(b)), 50 | }, nil 51 | }), 52 | } 53 | 54 | changes, err := client.ContainerDiff(context.Background(), "container_id") 55 | if err != nil { 56 | t.Fatal(err) 57 | } 58 | if len(changes) != 2 { 59 | t.Fatalf("expected an array of 2 changes, got %v", changes) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /service_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestServiceRemoveError(t *testing.T) { 16 | client := &Client{ 17 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 18 | } 19 | 20 | err := client.ServiceRemove(context.Background(), "service_id") 21 | assert.EqualError(t, err, "Error response from daemon: Server error") 22 | } 23 | 24 | func TestServiceRemoveNotFoundError(t *testing.T) { 25 | client := &Client{ 26 | client: newMockClient(errorMock(http.StatusNotFound, "missing")), 27 | } 28 | 29 | err := client.ServiceRemove(context.Background(), "service_id") 30 | assert.EqualError(t, err, "Error: No such service: service_id") 31 | assert.True(t, IsErrNotFound(err)) 32 | } 33 | 34 | func TestServiceRemove(t *testing.T) { 35 | expectedURL := "/services/service_id" 36 | 37 | client := &Client{ 38 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 39 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 40 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 41 | } 42 | if req.Method != "DELETE" { 43 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 44 | } 45 | return &http.Response{ 46 | StatusCode: http.StatusOK, 47 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 48 | }, nil 49 | }), 50 | } 51 | 52 | err := client.ServiceRemove(context.Background(), "service_id") 53 | if err != nil { 54 | t.Fatal(err) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /container_commit.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "net/url" 7 | 8 | "github.com/docker/distribution/reference" 9 | "docker.io/go-docker/api/types" 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | // ContainerCommit applies changes into a container and creates a new tagged image. 14 | func (cli *Client) ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) { 15 | var repository, tag string 16 | if options.Reference != "" { 17 | ref, err := reference.ParseNormalizedNamed(options.Reference) 18 | if err != nil { 19 | return types.IDResponse{}, err 20 | } 21 | 22 | if _, isCanonical := ref.(reference.Canonical); isCanonical { 23 | return types.IDResponse{}, errors.New("refusing to create a tag with a digest reference") 24 | } 25 | ref = reference.TagNameOnly(ref) 26 | 27 | if tagged, ok := ref.(reference.Tagged); ok { 28 | tag = tagged.Tag() 29 | } 30 | repository = reference.FamiliarName(ref) 31 | } 32 | 33 | query := url.Values{} 34 | query.Set("container", container) 35 | query.Set("repo", repository) 36 | query.Set("tag", tag) 37 | query.Set("comment", options.Comment) 38 | query.Set("author", options.Author) 39 | for _, change := range options.Changes { 40 | query.Add("changes", change) 41 | } 42 | if !options.Pause { 43 | query.Set("pause", "0") 44 | } 45 | 46 | var response types.IDResponse 47 | resp, err := cli.post(ctx, "/commit", query, options.Config, nil) 48 | if err != nil { 49 | return response, err 50 | } 51 | 52 | err = json.NewDecoder(resp.body).Decode(&response) 53 | ensureReaderClosed(resp) 54 | return response, err 55 | } 56 | -------------------------------------------------------------------------------- /image_history_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types/image" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestImageHistoryError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | _, err := client.ImageHistory(context.Background(), "nothing") 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server error, got %v", err) 23 | } 24 | } 25 | 26 | func TestImageHistory(t *testing.T) { 27 | expectedURL := "/images/image_id/history" 28 | client := &Client{ 29 | client: newMockClient(func(r *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(r.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL) 32 | } 33 | b, err := json.Marshal([]image.HistoryResponseItem{ 34 | { 35 | ID: "image_id1", 36 | Tags: []string{"tag1", "tag2"}, 37 | }, 38 | { 39 | ID: "image_id2", 40 | Tags: []string{"tag1", "tag2"}, 41 | }, 42 | }) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | return &http.Response{ 48 | StatusCode: http.StatusOK, 49 | Body: ioutil.NopCloser(bytes.NewReader(b)), 50 | }, nil 51 | }), 52 | } 53 | imageHistories, err := client.ImageHistory(context.Background(), "image_id") 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | if len(imageHistories) != 2 { 58 | t.Fatalf("expected 2 containers, got %v", imageHistories) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /image_search.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | 9 | "docker.io/go-docker/api/types" 10 | "docker.io/go-docker/api/types/filters" 11 | "docker.io/go-docker/api/types/registry" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | // ImageSearch makes the docker host to search by a term in a remote registry. 16 | // The list of results is not sorted in any fashion. 17 | func (cli *Client) ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) { 18 | var results []registry.SearchResult 19 | query := url.Values{} 20 | query.Set("term", term) 21 | query.Set("limit", fmt.Sprintf("%d", options.Limit)) 22 | 23 | if options.Filters.Len() > 0 { 24 | filterJSON, err := filters.ToJSON(options.Filters) 25 | if err != nil { 26 | return results, err 27 | } 28 | query.Set("filters", filterJSON) 29 | } 30 | 31 | resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth) 32 | if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { 33 | newAuthHeader, privilegeErr := options.PrivilegeFunc() 34 | if privilegeErr != nil { 35 | return results, privilegeErr 36 | } 37 | resp, err = cli.tryImageSearch(ctx, query, newAuthHeader) 38 | } 39 | if err != nil { 40 | return results, err 41 | } 42 | 43 | err = json.NewDecoder(resp.body).Decode(&results) 44 | ensureReaderClosed(resp) 45 | return results, err 46 | } 47 | 48 | func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) { 49 | headers := map[string][]string{"X-Registry-Auth": {registryAuth}} 50 | return cli.get(ctx, "/images/search", query, headers) 51 | } 52 | -------------------------------------------------------------------------------- /config_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestConfigRemoveUnsupported(t *testing.T) { 16 | client := &Client{ 17 | version: "1.29", 18 | client: &http.Client{}, 19 | } 20 | err := client.ConfigRemove(context.Background(), "config_id") 21 | assert.EqualError(t, err, `"config remove" requires API version 1.30, but the Docker daemon API version is 1.29`) 22 | } 23 | 24 | func TestConfigRemoveError(t *testing.T) { 25 | client := &Client{ 26 | version: "1.30", 27 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 28 | } 29 | 30 | err := client.ConfigRemove(context.Background(), "config_id") 31 | if err == nil || err.Error() != "Error response from daemon: Server error" { 32 | t.Fatalf("expected a Server Error, got %v", err) 33 | } 34 | } 35 | 36 | func TestConfigRemove(t *testing.T) { 37 | expectedURL := "/v1.30/configs/config_id" 38 | 39 | client := &Client{ 40 | version: "1.30", 41 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 42 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 43 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 44 | } 45 | if req.Method != "DELETE" { 46 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 47 | } 48 | return &http.Response{ 49 | StatusCode: http.StatusOK, 50 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 51 | }, nil 52 | }), 53 | } 54 | 55 | err := client.ConfigRemove(context.Background(), "config_id") 56 | if err != nil { 57 | t.Fatal(err) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /secret_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func TestSecretRemoveUnsupported(t *testing.T) { 16 | client := &Client{ 17 | version: "1.24", 18 | client: &http.Client{}, 19 | } 20 | err := client.SecretRemove(context.Background(), "secret_id") 21 | assert.EqualError(t, err, `"secret remove" requires API version 1.25, but the Docker daemon API version is 1.24`) 22 | } 23 | 24 | func TestSecretRemoveError(t *testing.T) { 25 | client := &Client{ 26 | version: "1.25", 27 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 28 | } 29 | 30 | err := client.SecretRemove(context.Background(), "secret_id") 31 | if err == nil || err.Error() != "Error response from daemon: Server error" { 32 | t.Fatalf("expected a Server Error, got %v", err) 33 | } 34 | } 35 | 36 | func TestSecretRemove(t *testing.T) { 37 | expectedURL := "/v1.25/secrets/secret_id" 38 | 39 | client := &Client{ 40 | version: "1.25", 41 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 42 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 43 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 44 | } 45 | if req.Method != "DELETE" { 46 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 47 | } 48 | return &http.Response{ 49 | StatusCode: http.StatusOK, 50 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 51 | }, nil 52 | }), 53 | } 54 | 55 | err := client.SecretRemove(context.Background(), "secret_id") 56 | if err != nil { 57 | t.Fatal(err) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /image_save_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "reflect" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | 13 | "strings" 14 | ) 15 | 16 | func TestImageSaveError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | _, err := client.ImageSave(context.Background(), []string{"nothing"}) 21 | if err == nil || err.Error() != "Error response from daemon: Server error" { 22 | t.Fatalf("expected a Server error, got %v", err) 23 | } 24 | } 25 | 26 | func TestImageSave(t *testing.T) { 27 | expectedURL := "/images/get" 28 | client := &Client{ 29 | client: newMockClient(func(r *http.Request) (*http.Response, error) { 30 | if !strings.HasPrefix(r.URL.Path, expectedURL) { 31 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL) 32 | } 33 | query := r.URL.Query() 34 | names := query["names"] 35 | expectedNames := []string{"image_id1", "image_id2"} 36 | if !reflect.DeepEqual(names, expectedNames) { 37 | return nil, fmt.Errorf("names not set in URL query properly. Expected %v, got %v", names, expectedNames) 38 | } 39 | 40 | return &http.Response{ 41 | StatusCode: http.StatusOK, 42 | Body: ioutil.NopCloser(bytes.NewReader([]byte("response"))), 43 | }, nil 44 | }), 45 | } 46 | saveResponse, err := client.ImageSave(context.Background(), []string{"image_id1", "image_id2"}) 47 | if err != nil { 48 | t.Fatal(err) 49 | } 50 | response, err := ioutil.ReadAll(saveResponse) 51 | if err != nil { 52 | t.Fatal(err) 53 | } 54 | saveResponse.Close() 55 | if string(response) != "response" { 56 | t.Fatalf("expected response to contain 'response', got %s", string(response)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /swarm_leave_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestSwarmLeaveError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | 19 | err := client.SwarmLeave(context.Background(), false) 20 | if err == nil || err.Error() != "Error response from daemon: Server error" { 21 | t.Fatalf("expected a Server Error, got %v", err) 22 | } 23 | } 24 | 25 | func TestSwarmLeave(t *testing.T) { 26 | expectedURL := "/swarm/leave" 27 | 28 | leaveCases := []struct { 29 | force bool 30 | expectedForce string 31 | }{ 32 | { 33 | expectedForce: "", 34 | }, 35 | { 36 | force: true, 37 | expectedForce: "1", 38 | }, 39 | } 40 | 41 | for _, leaveCase := range leaveCases { 42 | client := &Client{ 43 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 44 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 45 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 46 | } 47 | if req.Method != "POST" { 48 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 49 | } 50 | force := req.URL.Query().Get("force") 51 | if force != leaveCase.expectedForce { 52 | return nil, fmt.Errorf("force not set in URL query properly. expected '%s', got %s", leaveCase.expectedForce, force) 53 | } 54 | return &http.Response{ 55 | StatusCode: http.StatusOK, 56 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 57 | }, nil 58 | }), 59 | } 60 | 61 | err := client.SwarmLeave(context.Background(), leaveCase.force) 62 | if err != nil { 63 | t.Fatal(err) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /image_push.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "net/http" 7 | "net/url" 8 | 9 | "golang.org/x/net/context" 10 | 11 | "github.com/docker/distribution/reference" 12 | "docker.io/go-docker/api/types" 13 | ) 14 | 15 | // ImagePush requests the docker host to push an image to a remote registry. 16 | // It executes the privileged function if the operation is unauthorized 17 | // and it tries one more time. 18 | // It's up to the caller to handle the io.ReadCloser and close it properly. 19 | func (cli *Client) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) { 20 | ref, err := reference.ParseNormalizedNamed(image) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | if _, isCanonical := ref.(reference.Canonical); isCanonical { 26 | return nil, errors.New("cannot push a digest reference") 27 | } 28 | 29 | tag := "" 30 | name := reference.FamiliarName(ref) 31 | 32 | if nameTaggedRef, isNamedTagged := ref.(reference.NamedTagged); isNamedTagged { 33 | tag = nameTaggedRef.Tag() 34 | } 35 | 36 | query := url.Values{} 37 | query.Set("tag", tag) 38 | 39 | resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth) 40 | if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { 41 | newAuthHeader, privilegeErr := options.PrivilegeFunc() 42 | if privilegeErr != nil { 43 | return nil, privilegeErr 44 | } 45 | resp, err = cli.tryImagePush(ctx, name, query, newAuthHeader) 46 | } 47 | if err != nil { 48 | return nil, err 49 | } 50 | return resp.body, nil 51 | } 52 | 53 | func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (serverResponse, error) { 54 | headers := map[string][]string{"X-Registry-Auth": {registryAuth}} 55 | return cli.post(ctx, "/images/"+imageID+"/push", query, nil, headers) 56 | } 57 | -------------------------------------------------------------------------------- /node_inspect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types/swarm" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestNodeInspectError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | _, _, err := client.NodeInspectWithRaw(context.Background(), "nothing") 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestNodeInspectNodeNotFound(t *testing.T) { 28 | client := &Client{ 29 | client: newMockClient(errorMock(http.StatusNotFound, "Server error")), 30 | } 31 | 32 | _, _, err := client.NodeInspectWithRaw(context.Background(), "unknown") 33 | if err == nil || !IsErrNodeNotFound(err) { 34 | t.Fatalf("expected a nodeNotFoundError error, got %v", err) 35 | } 36 | } 37 | 38 | func TestNodeInspect(t *testing.T) { 39 | expectedURL := "/nodes/node_id" 40 | client := &Client{ 41 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 42 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 43 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 44 | } 45 | content, err := json.Marshal(swarm.Node{ 46 | ID: "node_id", 47 | }) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return &http.Response{ 52 | StatusCode: http.StatusOK, 53 | Body: ioutil.NopCloser(bytes.NewReader(content)), 54 | }, nil 55 | }), 56 | } 57 | 58 | nodeInspect, _, err := client.NodeInspectWithRaw(context.Background(), "node_id") 59 | if err != nil { 60 | t.Fatal(err) 61 | } 62 | if nodeInspect.ID != "node_id" { 63 | t.Fatalf("expected `node_id`, got %s", nodeInspect.ID) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /config_update_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types/swarm" 12 | "github.com/stretchr/testify/assert" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestConfigUpdateUnsupported(t *testing.T) { 17 | client := &Client{ 18 | version: "1.29", 19 | client: &http.Client{}, 20 | } 21 | err := client.ConfigUpdate(context.Background(), "config_id", swarm.Version{}, swarm.ConfigSpec{}) 22 | assert.EqualError(t, err, `"config update" requires API version 1.30, but the Docker daemon API version is 1.29`) 23 | } 24 | 25 | func TestConfigUpdateError(t *testing.T) { 26 | client := &Client{ 27 | version: "1.30", 28 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 29 | } 30 | 31 | err := client.ConfigUpdate(context.Background(), "config_id", swarm.Version{}, swarm.ConfigSpec{}) 32 | if err == nil || err.Error() != "Error response from daemon: Server error" { 33 | t.Fatalf("expected a Server Error, got %v", err) 34 | } 35 | } 36 | 37 | func TestConfigUpdate(t *testing.T) { 38 | expectedURL := "/v1.30/configs/config_id/update" 39 | 40 | client := &Client{ 41 | version: "1.30", 42 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 43 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 44 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 45 | } 46 | if req.Method != "POST" { 47 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 48 | } 49 | return &http.Response{ 50 | StatusCode: http.StatusOK, 51 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 52 | }, nil 53 | }), 54 | } 55 | 56 | err := client.ConfigUpdate(context.Background(), "config_id", swarm.Version{}, swarm.ConfigSpec{}) 57 | if err != nil { 58 | t.Fatal(err) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /secret_update_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types/swarm" 12 | "github.com/stretchr/testify/assert" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestSecretUpdateUnsupported(t *testing.T) { 17 | client := &Client{ 18 | version: "1.24", 19 | client: &http.Client{}, 20 | } 21 | err := client.SecretUpdate(context.Background(), "secret_id", swarm.Version{}, swarm.SecretSpec{}) 22 | assert.EqualError(t, err, `"secret update" requires API version 1.25, but the Docker daemon API version is 1.24`) 23 | } 24 | 25 | func TestSecretUpdateError(t *testing.T) { 26 | client := &Client{ 27 | version: "1.25", 28 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 29 | } 30 | 31 | err := client.SecretUpdate(context.Background(), "secret_id", swarm.Version{}, swarm.SecretSpec{}) 32 | if err == nil || err.Error() != "Error response from daemon: Server error" { 33 | t.Fatalf("expected a Server Error, got %v", err) 34 | } 35 | } 36 | 37 | func TestSecretUpdate(t *testing.T) { 38 | expectedURL := "/v1.25/secrets/secret_id/update" 39 | 40 | client := &Client{ 41 | version: "1.25", 42 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 43 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 44 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 45 | } 46 | if req.Method != "POST" { 47 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 48 | } 49 | return &http.Response{ 50 | StatusCode: http.StatusOK, 51 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 52 | }, nil 53 | }), 54 | } 55 | 56 | err := client.SecretUpdate(context.Background(), "secret_id", swarm.Version{}, swarm.SecretSpec{}) 57 | if err != nil { 58 | t.Fatal(err) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /network_disconnect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestNetworkDisconnectError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.NetworkDisconnect(context.Background(), "network_id", "container_id", false) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestNetworkDisconnect(t *testing.T) { 28 | expectedURL := "/networks/network_id/disconnect" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | 36 | if req.Method != "POST" { 37 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 38 | } 39 | 40 | var disconnect types.NetworkDisconnect 41 | if err := json.NewDecoder(req.Body).Decode(&disconnect); err != nil { 42 | return nil, err 43 | } 44 | 45 | if disconnect.Container != "container_id" { 46 | return nil, fmt.Errorf("expected 'container_id', got %s", disconnect.Container) 47 | } 48 | 49 | if !disconnect.Force { 50 | return nil, fmt.Errorf("expected Force to be true, got %v", disconnect.Force) 51 | } 52 | 53 | return &http.Response{ 54 | StatusCode: http.StatusOK, 55 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 56 | }, nil 57 | }), 58 | } 59 | 60 | err := client.NetworkDisconnect(context.Background(), "network_id", "container_id", true) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /api/types/plugin_responses.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "sort" 7 | ) 8 | 9 | // PluginsListResponse contains the response for the Engine API 10 | type PluginsListResponse []*Plugin 11 | 12 | // UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType 13 | func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error { 14 | versionIndex := len(p) 15 | prefixIndex := 0 16 | if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' { 17 | return fmt.Errorf("%q is not a plugin interface type", p) 18 | } 19 | p = p[1 : len(p)-1] 20 | loop: 21 | for i, b := range p { 22 | switch b { 23 | case '.': 24 | prefixIndex = i 25 | case '/': 26 | versionIndex = i 27 | break loop 28 | } 29 | } 30 | t.Prefix = string(p[:prefixIndex]) 31 | t.Capability = string(p[prefixIndex+1 : versionIndex]) 32 | if versionIndex < len(p) { 33 | t.Version = string(p[versionIndex+1:]) 34 | } 35 | return nil 36 | } 37 | 38 | // MarshalJSON implements json.Marshaler for PluginInterfaceType 39 | func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) { 40 | return json.Marshal(t.String()) 41 | } 42 | 43 | // String implements fmt.Stringer for PluginInterfaceType 44 | func (t PluginInterfaceType) String() string { 45 | return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version) 46 | } 47 | 48 | // PluginPrivilege describes a permission the user has to accept 49 | // upon installing a plugin. 50 | type PluginPrivilege struct { 51 | Name string 52 | Description string 53 | Value []string 54 | } 55 | 56 | // PluginPrivileges is a list of PluginPrivilege 57 | type PluginPrivileges []PluginPrivilege 58 | 59 | func (s PluginPrivileges) Len() int { 60 | return len(s) 61 | } 62 | 63 | func (s PluginPrivileges) Less(i, j int) bool { 64 | return s[i].Name < s[j].Name 65 | } 66 | 67 | func (s PluginPrivileges) Swap(i, j int) { 68 | sort.Strings(s[i].Value) 69 | sort.Strings(s[j].Value) 70 | s[i], s[j] = s[j], s[i] 71 | } 72 | -------------------------------------------------------------------------------- /api/types/events/events.go: -------------------------------------------------------------------------------- 1 | package events 2 | 3 | const ( 4 | // ContainerEventType is the event type that containers generate 5 | ContainerEventType = "container" 6 | // DaemonEventType is the event type that daemon generate 7 | DaemonEventType = "daemon" 8 | // ImageEventType is the event type that images generate 9 | ImageEventType = "image" 10 | // NetworkEventType is the event type that networks generate 11 | NetworkEventType = "network" 12 | // PluginEventType is the event type that plugins generate 13 | PluginEventType = "plugin" 14 | // VolumeEventType is the event type that volumes generate 15 | VolumeEventType = "volume" 16 | // ServiceEventType is the event type that services generate 17 | ServiceEventType = "service" 18 | // NodeEventType is the event type that nodes generate 19 | NodeEventType = "node" 20 | // SecretEventType is the event type that secrets generate 21 | SecretEventType = "secret" 22 | // ConfigEventType is the event type that configs generate 23 | ConfigEventType = "config" 24 | ) 25 | 26 | // Actor describes something that generates events, 27 | // like a container, or a network, or a volume. 28 | // It has a defined name and a set or attributes. 29 | // The container attributes are its labels, other actors 30 | // can generate these attributes from other properties. 31 | type Actor struct { 32 | ID string 33 | Attributes map[string]string 34 | } 35 | 36 | // Message represents the information an event contains 37 | type Message struct { 38 | // Deprecated information from JSONMessage. 39 | // With data only in container events. 40 | Status string `json:"status,omitempty"` 41 | ID string `json:"id,omitempty"` 42 | From string `json:"from,omitempty"` 43 | 44 | Type string 45 | Action string 46 | Actor Actor 47 | // Engine events are local scope. Cluster events are swarm scope. 48 | Scope string `json:"scope,omitempty"` 49 | 50 | Time int64 `json:"time,omitempty"` 51 | TimeNano int64 `json:"timeNano,omitempty"` 52 | } 53 | -------------------------------------------------------------------------------- /container_create.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | "strings" 7 | 8 | "docker.io/go-docker/api/types/container" 9 | "docker.io/go-docker/api/types/network" 10 | "docker.io/go-docker/api/types/versions" 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | type configWrapper struct { 15 | *container.Config 16 | HostConfig *container.HostConfig 17 | NetworkingConfig *network.NetworkingConfig 18 | } 19 | 20 | // ContainerCreate creates a new container based in the given configuration. 21 | // It can be associated with a name, but it's not mandatory. 22 | func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) { 23 | var response container.ContainerCreateCreatedBody 24 | 25 | if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil { 26 | return response, err 27 | } 28 | 29 | // When using API 1.24 and under, the client is responsible for removing the container 30 | if hostConfig != nil && versions.LessThan(cli.ClientVersion(), "1.25") { 31 | hostConfig.AutoRemove = false 32 | } 33 | 34 | query := url.Values{} 35 | if containerName != "" { 36 | query.Set("name", containerName) 37 | } 38 | 39 | body := configWrapper{ 40 | Config: config, 41 | HostConfig: hostConfig, 42 | NetworkingConfig: networkingConfig, 43 | } 44 | 45 | serverResp, err := cli.post(ctx, "/containers/create", query, body, nil) 46 | if err != nil { 47 | if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") { 48 | return response, objectNotFoundError{object: "image", id: config.Image} 49 | } 50 | return response, err 51 | } 52 | 53 | err = json.NewDecoder(serverResp.body).Decode(&response) 54 | ensureReaderClosed(serverResp) 55 | return response, err 56 | } 57 | -------------------------------------------------------------------------------- /container_start_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "golang.org/x/net/context" 13 | 14 | "docker.io/go-docker/api/types" 15 | ) 16 | 17 | func TestContainerStartError(t *testing.T) { 18 | client := &Client{ 19 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 20 | } 21 | err := client.ContainerStart(context.Background(), "nothing", types.ContainerStartOptions{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestContainerStart(t *testing.T) { 28 | expectedURL := "/containers/container_id/start" 29 | client := &Client{ 30 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 31 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 32 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 33 | } 34 | // we're not expecting any payload, but if one is supplied, check it is valid. 35 | if req.Header.Get("Content-Type") == "application/json" { 36 | var startConfig interface{} 37 | if err := json.NewDecoder(req.Body).Decode(&startConfig); err != nil { 38 | return nil, fmt.Errorf("Unable to parse json: %s", err) 39 | } 40 | } 41 | 42 | checkpoint := req.URL.Query().Get("checkpoint") 43 | if checkpoint != "checkpoint_id" { 44 | return nil, fmt.Errorf("checkpoint not set in URL query properly. Expected 'checkpoint_id', got %s", checkpoint) 45 | } 46 | 47 | return &http.Response{ 48 | StatusCode: http.StatusOK, 49 | Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 50 | }, nil 51 | }), 52 | } 53 | 54 | err := client.ContainerStart(context.Background(), "container_id", types.ContainerStartOptions{CheckpointID: "checkpoint_id"}) 55 | if err != nil { 56 | t.Fatal(err) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /node_remove_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "docker.io/go-docker/api/types" 12 | 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestNodeRemoveError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | err := client.NodeRemove(context.Background(), "node_id", types.NodeRemoveOptions{Force: false}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestNodeRemove(t *testing.T) { 28 | expectedURL := "/nodes/node_id" 29 | 30 | removeCases := []struct { 31 | force bool 32 | expectedForce string 33 | }{ 34 | { 35 | expectedForce: "", 36 | }, 37 | { 38 | force: true, 39 | expectedForce: "1", 40 | }, 41 | } 42 | 43 | for _, removeCase := range removeCases { 44 | client := &Client{ 45 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 46 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 47 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 48 | } 49 | if req.Method != "DELETE" { 50 | return nil, fmt.Errorf("expected DELETE method, got %s", req.Method) 51 | } 52 | force := req.URL.Query().Get("force") 53 | if force != removeCase.expectedForce { 54 | return nil, fmt.Errorf("force not set in URL query properly. expected '%s', got %s", removeCase.expectedForce, force) 55 | } 56 | 57 | return &http.Response{ 58 | StatusCode: http.StatusOK, 59 | Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))), 60 | }, nil 61 | }), 62 | } 63 | 64 | err := client.NodeRemove(context.Background(), "node_id", types.NodeRemoveOptions{Force: removeCase.force}) 65 | if err != nil { 66 | t.Fatal(err) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /container_attach.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "net/url" 5 | 6 | "docker.io/go-docker/api/types" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // ContainerAttach attaches a connection to a container in the server. 11 | // It returns a types.HijackedConnection with the hijacked connection 12 | // and the a reader to get output. It's up to the called to close 13 | // the hijacked connection by calling types.HijackedResponse.Close. 14 | // 15 | // The stream format on the response will be in one of two formats: 16 | // 17 | // If the container is using a TTY, there is only a single stream (stdout), and 18 | // data is copied directly from the container output stream, no extra 19 | // multiplexing or headers. 20 | // 21 | // If the container is *not* using a TTY, streams for stdout and stderr are 22 | // multiplexed. 23 | // The format of the multiplexed stream is as follows: 24 | // 25 | // [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT} 26 | // 27 | // STREAM_TYPE can be 1 for stdout and 2 for stderr 28 | // 29 | // SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian. 30 | // This is the size of OUTPUT. 31 | // 32 | // You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this 33 | // stream. 34 | func (cli *Client) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) { 35 | query := url.Values{} 36 | if options.Stream { 37 | query.Set("stream", "1") 38 | } 39 | if options.Stdin { 40 | query.Set("stdin", "1") 41 | } 42 | if options.Stdout { 43 | query.Set("stdout", "1") 44 | } 45 | if options.Stderr { 46 | query.Set("stderr", "1") 47 | } 48 | if options.DetachKeys != "" { 49 | query.Set("detachKeys", options.DetachKeys) 50 | } 51 | if options.Logs { 52 | query.Set("logs", "1") 53 | } 54 | 55 | headers := map[string][]string{"Content-Type": {"text/plain"}} 56 | return cli.postHijacked(ctx, "/containers/"+container+"/attach", query, nil, headers) 57 | } 58 | -------------------------------------------------------------------------------- /container_stats_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | "testing" 10 | 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func TestContainerStatsError(t *testing.T) { 15 | client := &Client{ 16 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 17 | } 18 | _, err := client.ContainerStats(context.Background(), "nothing", false) 19 | if err == nil || err.Error() != "Error response from daemon: Server error" { 20 | t.Fatalf("expected a Server Error, got %v", err) 21 | } 22 | } 23 | 24 | func TestContainerStats(t *testing.T) { 25 | expectedURL := "/containers/container_id/stats" 26 | cases := []struct { 27 | stream bool 28 | expectedStream string 29 | }{ 30 | { 31 | expectedStream: "0", 32 | }, 33 | { 34 | stream: true, 35 | expectedStream: "1", 36 | }, 37 | } 38 | for _, c := range cases { 39 | client := &Client{ 40 | client: newMockClient(func(r *http.Request) (*http.Response, error) { 41 | if !strings.HasPrefix(r.URL.Path, expectedURL) { 42 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL) 43 | } 44 | 45 | query := r.URL.Query() 46 | stream := query.Get("stream") 47 | if stream != c.expectedStream { 48 | return nil, fmt.Errorf("stream not set in URL query properly. Expected '%s', got %s", c.expectedStream, stream) 49 | } 50 | 51 | return &http.Response{ 52 | StatusCode: http.StatusOK, 53 | Body: ioutil.NopCloser(bytes.NewReader([]byte("response"))), 54 | }, nil 55 | }), 56 | } 57 | resp, err := client.ContainerStats(context.Background(), "container_id", c.stream) 58 | if err != nil { 59 | t.Fatal(err) 60 | } 61 | defer resp.Body.Close() 62 | content, err := ioutil.ReadAll(resp.Body) 63 | if err != nil { 64 | t.Fatal(err) 65 | } 66 | if string(content) != "response" { 67 | t.Fatalf("expected response to contain 'response', got %s", string(content)) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker.io/go-docker 2 | Official Go SDK for Docker 3 | 4 | ## Dependency management tool is required 5 | 6 | This repository describes its dependencies in a `Gopkg.toml` file as created by the [`dep`](https://github.com/golang/dep#setup) tool. 7 | 8 | It also uses semantic versioning, and requires its users to use `dep`-compatible dependency management tools to ensure stability and avoid breaking changes. 9 | 10 | The canonical import path is `docker.io/go-docker`. 11 | 12 | Note: you may download it with `go get -d docker.io/go-docker`, but if you omit `-d`, you may have compile errors. Hence the `dep` approach is preferred. 13 | 14 | ### How to use `dep` in your project 15 | 16 | You can use any tool that is compatible, but in the examples below we are using `dep`. 17 | 18 | #### Adding dependency to `vendor/` 19 | 20 | ```bash 21 | $ cd $GOPATH/src/myproject 22 | $ dep init # only if first time use 23 | $ dep ensure -add docker.io/go-docker@v1 # to use the latest version of v1.x.y 24 | ``` 25 | 26 | #### Updating dependency 27 | 28 | ```bash 29 | $ cd $GOPATH/src/myproject 30 | $ edit Gopkg.toml 31 | $ dep ensure 32 | ``` 33 | 34 | ## Reference Documentation 35 | 36 | [godoc.org/docker.io/go-docker](https://godoc.org/docker.io/go-docker) 37 | 38 | ## Issues 39 | 40 | Feel free to open issues on the Github issue tracker. 41 | 42 | ## Migrating from `github.com/docker/docker/client` 43 | 44 | If you were previously depending on `github.com/docker/docker/client`, you can run the following in bash 45 | to start using `docker.io/go-docker` v1 and benefiting from semantic versioning guarantees. 46 | 47 | ```bash 48 | files=( $(find . -name '*.go' -not -path './vendor/*') ) 49 | 50 | for rule in \ 51 | 's|"github.com/docker/docker/api|"docker.io/go-docker/api|' \ 52 | 's|^([[:space:]]+)"github.com/docker/docker/client|\1client "docker.io/go-docker|' \ 53 | 's|"github.com/docker/docker/client|"docker.io/go-docker|' \ 54 | ; do 55 | sed -i -E "$rule" ${files[*]} 56 | done 57 | ``` 58 | 59 | Note that if you aliased any import they will be preserved. 60 | -------------------------------------------------------------------------------- /checkpoint_list_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "golang.org/x/net/context" 14 | ) 15 | 16 | func TestCheckpointListError(t *testing.T) { 17 | client := &Client{ 18 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 19 | } 20 | 21 | _, err := client.CheckpointList(context.Background(), "container_id", types.CheckpointListOptions{}) 22 | if err == nil || err.Error() != "Error response from daemon: Server error" { 23 | t.Fatalf("expected a Server Error, got %v", err) 24 | } 25 | } 26 | 27 | func TestCheckpointList(t *testing.T) { 28 | expectedURL := "/containers/container_id/checkpoints" 29 | 30 | client := &Client{ 31 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 32 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 33 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 34 | } 35 | content, err := json.Marshal([]types.Checkpoint{ 36 | { 37 | Name: "checkpoint", 38 | }, 39 | }) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return &http.Response{ 44 | StatusCode: http.StatusOK, 45 | Body: ioutil.NopCloser(bytes.NewReader(content)), 46 | }, nil 47 | }), 48 | } 49 | 50 | checkpoints, err := client.CheckpointList(context.Background(), "container_id", types.CheckpointListOptions{}) 51 | if err != nil { 52 | t.Fatal(err) 53 | } 54 | if len(checkpoints) != 1 { 55 | t.Fatalf("expected 1 checkpoint, got %v", checkpoints) 56 | } 57 | } 58 | 59 | func TestCheckpointListContainerNotFound(t *testing.T) { 60 | client := &Client{ 61 | client: newMockClient(errorMock(http.StatusNotFound, "Server error")), 62 | } 63 | 64 | _, err := client.CheckpointList(context.Background(), "unknown", types.CheckpointListOptions{}) 65 | if err == nil || !IsErrContainerNotFound(err) { 66 | t.Fatalf("expected a containerNotFound error, got %v", err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /service_inspect_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "docker.io/go-docker/api/types/swarm" 14 | "golang.org/x/net/context" 15 | ) 16 | 17 | func TestServiceInspectError(t *testing.T) { 18 | client := &Client{ 19 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 20 | } 21 | 22 | _, _, err := client.ServiceInspectWithRaw(context.Background(), "nothing", types.ServiceInspectOptions{}) 23 | if err == nil || err.Error() != "Error response from daemon: Server error" { 24 | t.Fatalf("expected a Server Error, got %v", err) 25 | } 26 | } 27 | 28 | func TestServiceInspectServiceNotFound(t *testing.T) { 29 | client := &Client{ 30 | client: newMockClient(errorMock(http.StatusNotFound, "Server error")), 31 | } 32 | 33 | _, _, err := client.ServiceInspectWithRaw(context.Background(), "unknown", types.ServiceInspectOptions{}) 34 | if err == nil || !IsErrServiceNotFound(err) { 35 | t.Fatalf("expected a serviceNotFoundError error, got %v", err) 36 | } 37 | } 38 | 39 | func TestServiceInspect(t *testing.T) { 40 | expectedURL := "/services/service_id" 41 | client := &Client{ 42 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 43 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 44 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 45 | } 46 | content, err := json.Marshal(swarm.Service{ 47 | ID: "service_id", 48 | }) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return &http.Response{ 53 | StatusCode: http.StatusOK, 54 | Body: ioutil.NopCloser(bytes.NewReader(content)), 55 | }, nil 56 | }), 57 | } 58 | 59 | serviceInspect, _, err := client.ServiceInspectWithRaw(context.Background(), "service_id", types.ServiceInspectOptions{}) 60 | if err != nil { 61 | t.Fatal(err) 62 | } 63 | if serviceInspect.ID != "service_id" { 64 | t.Fatalf("expected `service_id`, got %s", serviceInspect.ID) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /container_logs.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "io" 5 | "net/url" 6 | "time" 7 | 8 | "golang.org/x/net/context" 9 | 10 | "docker.io/go-docker/api/types" 11 | timetypes "docker.io/go-docker/api/types/time" 12 | ) 13 | 14 | // ContainerLogs returns the logs generated by a container in an io.ReadCloser. 15 | // It's up to the caller to close the stream. 16 | // 17 | // The stream format on the response will be in one of two formats: 18 | // 19 | // If the container is using a TTY, there is only a single stream (stdout), and 20 | // data is copied directly from the container output stream, no extra 21 | // multiplexing or headers. 22 | // 23 | // If the container is *not* using a TTY, streams for stdout and stderr are 24 | // multiplexed. 25 | // The format of the multiplexed stream is as follows: 26 | // 27 | // [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT} 28 | // 29 | // STREAM_TYPE can be 1 for stdout and 2 for stderr 30 | // 31 | // SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian. 32 | // This is the size of OUTPUT. 33 | // 34 | // You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this 35 | // stream. 36 | func (cli *Client) ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) { 37 | query := url.Values{} 38 | if options.ShowStdout { 39 | query.Set("stdout", "1") 40 | } 41 | 42 | if options.ShowStderr { 43 | query.Set("stderr", "1") 44 | } 45 | 46 | if options.Since != "" { 47 | ts, err := timetypes.GetTimestamp(options.Since, time.Now()) 48 | if err != nil { 49 | return nil, err 50 | } 51 | query.Set("since", ts) 52 | } 53 | 54 | if options.Timestamps { 55 | query.Set("timestamps", "1") 56 | } 57 | 58 | if options.Details { 59 | query.Set("details", "1") 60 | } 61 | 62 | if options.Follow { 63 | query.Set("follow", "1") 64 | } 65 | query.Set("tail", options.Tail) 66 | 67 | resp, err := cli.get(ctx, "/containers/"+container+"/logs", query, nil) 68 | if err != nil { 69 | return nil, err 70 | } 71 | return resp.body, nil 72 | } 73 | -------------------------------------------------------------------------------- /config_create_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "docker.io/go-docker/api/types/swarm" 14 | "github.com/stretchr/testify/assert" 15 | "golang.org/x/net/context" 16 | ) 17 | 18 | func TestConfigCreateUnsupported(t *testing.T) { 19 | client := &Client{ 20 | version: "1.29", 21 | client: &http.Client{}, 22 | } 23 | _, err := client.ConfigCreate(context.Background(), swarm.ConfigSpec{}) 24 | assert.EqualError(t, err, `"config create" requires API version 1.30, but the Docker daemon API version is 1.29`) 25 | } 26 | 27 | func TestConfigCreateError(t *testing.T) { 28 | client := &Client{ 29 | version: "1.30", 30 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 31 | } 32 | _, err := client.ConfigCreate(context.Background(), swarm.ConfigSpec{}) 33 | if err == nil || err.Error() != "Error response from daemon: Server error" { 34 | t.Fatalf("expected a Server Error, got %v", err) 35 | } 36 | } 37 | 38 | func TestConfigCreate(t *testing.T) { 39 | expectedURL := "/v1.30/configs/create" 40 | client := &Client{ 41 | version: "1.30", 42 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 43 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 44 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 45 | } 46 | if req.Method != "POST" { 47 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 48 | } 49 | b, err := json.Marshal(types.ConfigCreateResponse{ 50 | ID: "test_config", 51 | }) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return &http.Response{ 56 | StatusCode: http.StatusCreated, 57 | Body: ioutil.NopCloser(bytes.NewReader(b)), 58 | }, nil 59 | }), 60 | } 61 | 62 | r, err := client.ConfigCreate(context.Background(), swarm.ConfigSpec{}) 63 | if err != nil { 64 | t.Fatal(err) 65 | } 66 | if r.ID != "test_config" { 67 | t.Fatalf("expected `test_config`, got %s", r.ID) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /secret_create_test.go: -------------------------------------------------------------------------------- 1 | package docker // import "docker.io/go-docker" 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | "strings" 10 | "testing" 11 | 12 | "docker.io/go-docker/api/types" 13 | "docker.io/go-docker/api/types/swarm" 14 | "github.com/stretchr/testify/assert" 15 | "golang.org/x/net/context" 16 | ) 17 | 18 | func TestSecretCreateUnsupported(t *testing.T) { 19 | client := &Client{ 20 | version: "1.24", 21 | client: &http.Client{}, 22 | } 23 | _, err := client.SecretCreate(context.Background(), swarm.SecretSpec{}) 24 | assert.EqualError(t, err, `"secret create" requires API version 1.25, but the Docker daemon API version is 1.24`) 25 | } 26 | 27 | func TestSecretCreateError(t *testing.T) { 28 | client := &Client{ 29 | version: "1.25", 30 | client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 31 | } 32 | _, err := client.SecretCreate(context.Background(), swarm.SecretSpec{}) 33 | if err == nil || err.Error() != "Error response from daemon: Server error" { 34 | t.Fatalf("expected a Server Error, got %v", err) 35 | } 36 | } 37 | 38 | func TestSecretCreate(t *testing.T) { 39 | expectedURL := "/v1.25/secrets/create" 40 | client := &Client{ 41 | version: "1.25", 42 | client: newMockClient(func(req *http.Request) (*http.Response, error) { 43 | if !strings.HasPrefix(req.URL.Path, expectedURL) { 44 | return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 45 | } 46 | if req.Method != "POST" { 47 | return nil, fmt.Errorf("expected POST method, got %s", req.Method) 48 | } 49 | b, err := json.Marshal(types.SecretCreateResponse{ 50 | ID: "test_secret", 51 | }) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return &http.Response{ 56 | StatusCode: http.StatusCreated, 57 | Body: ioutil.NopCloser(bytes.NewReader(b)), 58 | }, nil 59 | }), 60 | } 61 | 62 | r, err := client.SecretCreate(context.Background(), swarm.SecretSpec{}) 63 | if err != nil { 64 | t.Fatal(err) 65 | } 66 | if r.ID != "test_secret" { 67 | t.Fatalf("expected `test_secret`, got %s", r.ID) 68 | } 69 | } 70 | --------------------------------------------------------------------------------