From 78049ad2400a750f803ffdd324139817ff4a1d43 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Wed, 6 Aug 2014 10:30:47 -0700 Subject: [PATCH] agent: ACL endpoint tests --- command/agent/acl_endpoint.go | 6 +- command/agent/acl_endpoint_test.go | 158 +++++++++++++++++++++++++++++ command/agent/http.go | 2 +- consul/acl_endpoint.go | 28 +++-- 4 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 command/agent/acl_endpoint_test.go diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index cfec2c8f13..0e291ebbcb 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -18,7 +18,7 @@ func (s *HTTPServer) ACLDelete(resp http.ResponseWriter, req *http.Request) (int } s.parseDC(req, &args.Datacenter) - // Pull out the session id + // Pull out the acl id args.ACL.ID = strings.TrimPrefix(req.URL.Path, "/v1/acl/delete/") if args.ACL.ID == "" { resp.WriteHeader(400) @@ -95,7 +95,7 @@ func (s *HTTPServer) ACLClone(resp http.ResponseWriter, req *http.Request) (inte return nil, nil } - // Pull out the session id + // Pull out the acl id args.ACL = strings.TrimPrefix(req.URL.Path, "/v1/acl/clone/") if args.ACL == "" { resp.WriteHeader(400) @@ -140,7 +140,7 @@ func (s *HTTPServer) ACLGet(resp http.ResponseWriter, req *http.Request) (interf return nil, nil } - // Pull out the session id + // Pull out the acl id args.ACL = strings.TrimPrefix(req.URL.Path, "/v1/acl/info/") if args.ACL == "" { resp.WriteHeader(400) diff --git a/command/agent/acl_endpoint_test.go b/command/agent/acl_endpoint_test.go new file mode 100644 index 0000000000..fc7f29766f --- /dev/null +++ b/command/agent/acl_endpoint_test.go @@ -0,0 +1,158 @@ +package agent + +import ( + "bytes" + "encoding/json" + "github.com/hashicorp/consul/consul/structs" + "net/http" + "net/http/httptest" + "testing" +) + +func makeTestACL(t *testing.T, srv *HTTPServer) string { + body := bytes.NewBuffer(nil) + enc := json.NewEncoder(body) + raw := map[string]interface{}{ + "Name": "User Token", + "Type": "client", + "Rules": "", + } + enc.Encode(raw) + + req, err := http.NewRequest("PUT", "/v1/acl/create", body) + if err != nil { + t.Fatalf("err: %v", err) + } + resp := httptest.NewRecorder() + obj, err := srv.ACLCreate(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + aclResp := obj.(aclCreateResponse) + return aclResp.ID +} + +func TestACLUpdate(t *testing.T) { + httpTest(t, func(srv *HTTPServer) { + id := makeTestACL(t, srv) + + body := bytes.NewBuffer(nil) + enc := json.NewEncoder(body) + raw := map[string]interface{}{ + "ID": id, + "Name": "User Token 2", + "Type": "client", + "Rules": "", + } + enc.Encode(raw) + + req, err := http.NewRequest("PUT", "/v1/acl/update", body) + if err != nil { + t.Fatalf("err: %v", err) + } + resp := httptest.NewRecorder() + obj, err := srv.ACLUpdate(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + aclResp := obj.(aclCreateResponse) + if aclResp.ID != id { + t.Fatalf("bad: %v", aclResp) + } + }) +} + +func TestACLDelete(t *testing.T) { + httpTest(t, func(srv *HTTPServer) { + id := makeTestACL(t, srv) + req, err := http.NewRequest("PUT", "/v1/session/delete/"+id, nil) + resp := httptest.NewRecorder() + obj, err := srv.ACLDelete(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp := obj.(bool); !resp { + t.Fatalf("should work") + } + }) +} + +func TestACLClone(t *testing.T) { + httpTest(t, func(srv *HTTPServer) { + id := makeTestACL(t, srv) + + req, err := http.NewRequest("GET", + "/v1/acl/clone/"+id, nil) + resp := httptest.NewRecorder() + obj, err := srv.ACLClone(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + aclResp, ok := obj.(aclCreateResponse) + if !ok { + t.Fatalf("should work: %#v %#v", obj, resp) + } + if aclResp.ID == id { + t.Fatalf("bad id") + } + + req, err = http.NewRequest("GET", + "/v1/acl/info/"+aclResp.ID, nil) + resp = httptest.NewRecorder() + obj, err = srv.ACLGet(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + respObj, ok := obj.(structs.ACLs) + if !ok { + t.Fatalf("should work") + } + if len(respObj) != 1 { + t.Fatalf("bad: %v", respObj) + } + }) +} + +func TestACLGet(t *testing.T) { + httpTest(t, func(srv *HTTPServer) { + id := makeTestACL(t, srv) + + req, err := http.NewRequest("GET", + "/v1/acl/info/"+id, nil) + resp := httptest.NewRecorder() + obj, err := srv.ACLGet(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + respObj, ok := obj.(structs.ACLs) + if !ok { + t.Fatalf("should work") + } + if len(respObj) != 1 { + t.Fatalf("bad: %v", respObj) + } + }) +} + +func TestACLList(t *testing.T) { + httpTest(t, func(srv *HTTPServer) { + var ids []string + for i := 0; i < 10; i++ { + ids = append(ids, makeTestACL(t, srv)) + } + + req, err := http.NewRequest("GET", "/v1/acl/list", nil) + resp := httptest.NewRecorder() + obj, err := srv.ACLList(resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + respObj, ok := obj.(structs.ACLs) + if !ok { + t.Fatalf("should work") + } + if len(respObj) != 10 { + t.Fatalf("bad: %v", respObj) + } + }) +} diff --git a/command/agent/http.go b/command/agent/http.go index e40a883f82..45443547b2 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -100,9 +100,9 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) { s.mux.HandleFunc("/v1/session/list", s.wrap(s.SessionList)) s.mux.HandleFunc("/v1/acl/create", s.wrap(s.ACLCreate)) + s.mux.HandleFunc("/v1/acl/update", s.wrap(s.ACLUpdate)) s.mux.HandleFunc("/v1/acl/delete/", s.wrap(s.ACLDelete)) s.mux.HandleFunc("/v1/acl/info/", s.wrap(s.ACLGet)) - s.mux.HandleFunc("/v1/acl/update/", s.wrap(s.ACLUpdate)) s.mux.HandleFunc("/v1/acl/clone/", s.wrap(s.ACLClone)) s.mux.HandleFunc("/v1/acl/list", s.wrap(s.ACLList)) diff --git a/consul/acl_endpoint.go b/consul/acl_endpoint.go index ac9b0cdab1..89c7ee6d6c 100644 --- a/consul/acl_endpoint.go +++ b/consul/acl_endpoint.go @@ -20,16 +20,26 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error { } defer metrics.MeasureSince([]string{"consul", "acl", "apply"}, time.Now()) - // Verify the args - switch args.ACL.Type { - case structs.ACLTypeClient: - case structs.ACLTypeManagement: - default: - return fmt.Errorf("Invalid ACL Type") - } + switch args.Op { + case structs.ACLSet: + // Verify the ACL type + switch args.ACL.Type { + case structs.ACLTypeClient: + case structs.ACLTypeManagement: + default: + return fmt.Errorf("Invalid ACL Type") + } - // TODO: Verify ACL compiles... - if args.Op == structs.ACLSet { + // TODO: Validate the rules compile + // + + case structs.ACLDelete: + if args.ACL.ID == "" { + return fmt.Errorf("Missing ACL ID") + } + + default: + return fmt.Errorf("Invalid ACL Operation") } // Apply the update