Adding force to the RemoveNode API

Signed-off-by: Diogo Monica <diogo.monica@gmail.com>
This commit is contained in:
Diogo Monica 2016-07-27 16:51:52 -07:00
Родитель 3d1601b9d2
Коммит 61cb872d9d
4 изменённых файлов: 60 добавлений и 22 удалений

Просмотреть файл

@ -94,7 +94,7 @@ type NetworkAPIClient interface {
type NodeAPIClient interface {
NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error)
NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
NodeRemove(ctx context.Context, nodeID string) error
NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error
NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error
}

Просмотреть файл

@ -1,10 +1,21 @@
package client
import "golang.org/x/net/context"
import (
"net/url"
"github.com/docker/engine-api/types"
"golang.org/x/net/context"
)
// NodeRemove removes a Node.
func (cli *Client) NodeRemove(ctx context.Context, nodeID string) error {
resp, err := cli.delete(ctx, "/nodes/"+nodeID, nil, nil)
func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error {
query := url.Values{}
if options.Force {
query.Set("force", "1")
}
resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil)
ensureReaderClosed(resp)
return err
}

Просмотреть файл

@ -8,6 +8,8 @@ import (
"strings"
"testing"
"github.com/docker/engine-api/types"
"golang.org/x/net/context"
)
@ -16,7 +18,7 @@ func TestNodeRemoveError(t *testing.T) {
transport: newMockClient(nil, errorMock(http.StatusInternalServerError, "Server error")),
}
err := client.NodeRemove(context.Background(), "node_id")
err := client.NodeRemove(context.Background(), "node_id", types.NodeRemoveOptions{Force: false})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
@ -25,23 +27,43 @@ func TestNodeRemoveError(t *testing.T) {
func TestNodeRemove(t *testing.T) {
expectedURL := "/nodes/node_id"
client := &Client{
transport: newMockClient(nil, 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
}),
removeCases := []struct {
force bool
expectedForce string
}{
{
expectedForce: "",
},
{
force: true,
expectedForce: "1",
},
}
err := client.NodeRemove(context.Background(), "node_id")
if err != nil {
t.Fatal(err)
for _, removeCase := range removeCases {
client := &Client{
transport: newMockClient(nil, 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)
}
force := req.URL.Query().Get("force")
if force != removeCase.expectedForce {
return nil, fmt.Errorf("force not set in URL query properly. expected '%s', got %s", removeCase.expectedForce, force)
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))),
}, nil
}),
}
err := client.NodeRemove(context.Background(), "node_id", types.NodeRemoveOptions{Force: removeCase.force})
if err != nil {
t.Fatal(err)
}
}
}

Просмотреть файл

@ -241,11 +241,16 @@ func (v VersionResponse) ServerOK() bool {
return v.Server != nil
}
// NodeListOptions holds parameters to list nodes with.
// NodeListOptions holds parameters to list nodes with.
type NodeListOptions struct {
Filter filters.Args
}
// NodeRemoveOptions holds parameters to remove nodes with.
type NodeRemoveOptions struct {
Force bool
}
// ServiceCreateOptions contains the options to use when creating a service.
type ServiceCreateOptions struct {
// EncodedRegistryAuth is the encoded registry authorization credentials to