Skip to content

Commit

Permalink
Add configs support to client
Browse files Browse the repository at this point in the history
Signed-off-by: Aaron Lehmann <[email protected]>
  • Loading branch information
aaronlehmann committed May 11, 2017
1 parent 7728557 commit 1027381
Show file tree
Hide file tree
Showing 12 changed files with 463 additions and 0 deletions.
22 changes: 22 additions & 0 deletions client/config_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package client

import (
"encoding/json"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

// ConfigCreate creates a new Config.
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
var response types.ConfigCreateResponse
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
if err != nil {
return response, err
}

err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}
57 changes: 57 additions & 0 deletions client/config_create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

func TestConfigCreateError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ConfigCreate(context.Background(), swarm.ConfigSpec{})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
}

func TestConfigCreate(t *testing.T) {
expectedURL := "/configs/create"
client := &Client{
client: newMockClient(func(req *http.Request) (*http.Response, error) {
if !strings.HasPrefix(req.URL.Path, expectedURL) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
}
if req.Method != "POST" {
return nil, fmt.Errorf("expected POST method, got %s", req.Method)
}
b, err := json.Marshal(types.ConfigCreateResponse{
ID: "test_config",
})
if err != nil {
return nil, err
}
return &http.Response{
StatusCode: http.StatusCreated,
Body: ioutil.NopCloser(bytes.NewReader(b)),
}, nil
}),
}

r, err := client.ConfigCreate(context.Background(), swarm.ConfigSpec{})
if err != nil {
t.Fatal(err)
}
if r.ID != "test_config" {
t.Fatalf("expected `test_config`, got %s", r.ID)
}
}
34 changes: 34 additions & 0 deletions client/config_inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package client

import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"

"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

// ConfigInspectWithRaw returns the config information with raw data
func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
return swarm.Config{}, nil, configNotFoundError{id}
}
return swarm.Config{}, nil, err
}
defer ensureReaderClosed(resp)

body, err := ioutil.ReadAll(resp.body)
if err != nil {
return swarm.Config{}, nil, err
}

var config swarm.Config
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&config)

return config, body, err
}
65 changes: 65 additions & 0 deletions client/config_inspect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"

"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

func TestConfigInspectError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}

_, _, err := client.ConfigInspectWithRaw(context.Background(), "nothing")
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
}

func TestConfigInspectConfigNotFound(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
}

_, _, err := client.ConfigInspectWithRaw(context.Background(), "unknown")
if err == nil || !IsErrConfigNotFound(err) {
t.Fatalf("expected a configNotFoundError error, got %v", err)
}
}

func TestConfigInspect(t *testing.T) {
expectedURL := "/configs/config_id"
client := &Client{
client: newMockClient(func(req *http.Request) (*http.Response, error) {
if !strings.HasPrefix(req.URL.Path, expectedURL) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
}
content, err := json.Marshal(swarm.Config{
ID: "config_id",
})
if err != nil {
return nil, err
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader(content)),
}, nil
}),
}

configInspect, _, err := client.ConfigInspectWithRaw(context.Background(), "config_id")
if err != nil {
t.Fatal(err)
}
if configInspect.ID != "config_id" {
t.Fatalf("expected `config_id`, got %s", configInspect.ID)
}
}
35 changes: 35 additions & 0 deletions client/config_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package client

import (
"encoding/json"
"net/url"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

// ConfigList returns the list of configs.
func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
query := url.Values{}

if options.Filters.Len() > 0 {
filterJSON, err := filters.ToParam(options.Filters)
if err != nil {
return nil, err
}

query.Set("filters", filterJSON)
}

resp, err := cli.get(ctx, "/configs", query, nil)
if err != nil {
return nil, err
}

var configs []swarm.Config
err = json.NewDecoder(resp.body).Decode(&configs)
ensureReaderClosed(resp)
return configs, err
}
94 changes: 94 additions & 0 deletions client/config_list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

func TestConfigListError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}

_, err := client.ConfigList(context.Background(), types.ConfigListOptions{})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
}

func TestConfigList(t *testing.T) {
expectedURL := "/configs"

filters := filters.NewArgs()
filters.Add("label", "label1")
filters.Add("label", "label2")

listCases := []struct {
options types.ConfigListOptions
expectedQueryParams map[string]string
}{
{
options: types.ConfigListOptions{},
expectedQueryParams: map[string]string{
"filters": "",
},
},
{
options: types.ConfigListOptions{
Filters: filters,
},
expectedQueryParams: map[string]string{
"filters": `{"label":{"label1":true,"label2":true}}`,
},
},
}
for _, listCase := range listCases {
client := &Client{
client: newMockClient(func(req *http.Request) (*http.Response, error) {
if !strings.HasPrefix(req.URL.Path, expectedURL) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
}
query := req.URL.Query()
for key, expected := range listCase.expectedQueryParams {
actual := query.Get(key)
if actual != expected {
return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
}
}
content, err := json.Marshal([]swarm.Config{
{
ID: "config_id1",
},
{
ID: "config_id2",
},
})
if err != nil {
return nil, err
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader(content)),
}, nil
}),
}

configs, err := client.ConfigList(context.Background(), listCase.options)
if err != nil {
t.Fatal(err)
}
if len(configs) != 2 {
t.Fatalf("expected 2 configs, got %v", configs)
}
}
}
10 changes: 10 additions & 0 deletions client/config_remove.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package client

import "golang.org/x/net/context"

// ConfigRemove removes a Config.
func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
ensureReaderClosed(resp)
return err
}
47 changes: 47 additions & 0 deletions client/config_remove_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package client

import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"

"golang.org/x/net/context"
)

func TestConfigRemoveError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}

err := client.ConfigRemove(context.Background(), "config_id")
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
}

func TestConfigRemove(t *testing.T) {
expectedURL := "/configs/config_id"

client := &Client{
client: newMockClient(func(req *http.Request) (*http.Response, error) {
if !strings.HasPrefix(req.URL.Path, expectedURL) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
}
if req.Method != "DELETE" {
return nil, fmt.Errorf("expected DELETE method, got %s", req.Method)
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))),
}, nil
}),
}

err := client.ConfigRemove(context.Background(), "config_id")
if err != nil {
t.Fatal(err)
}
}
18 changes: 18 additions & 0 deletions client/config_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package client

import (
"net/url"
"strconv"

"github.com/docker/docker/api/types/swarm"
"golang.org/x/net/context"
)

// ConfigUpdate attempts to updates a Config
func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error {
query := url.Values{}
query.Set("version", strconv.FormatUint(version.Index, 10))
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)
ensureReaderClosed(resp)
return err
}
Loading

0 comments on commit 1027381

Please sign in to comment.