http: /v1/sys/mount endpoint

This commit is contained in:
Mitchell Hashimoto 2015-03-16 10:36:29 -07:00
parent 3d3ac3ff7a
commit e3a796028e
5 changed files with 100 additions and 4 deletions

View file

@ -15,7 +15,8 @@ func Handler(core *vault.Core) http.Handler {
mux.Handle("/v1/sys/seal-status", handleSysSealStatus(core)) mux.Handle("/v1/sys/seal-status", handleSysSealStatus(core))
mux.Handle("/v1/sys/seal", handleSysSeal(core)) mux.Handle("/v1/sys/seal", handleSysSeal(core))
mux.Handle("/v1/sys/unseal", handleSysUnseal(core)) mux.Handle("/v1/sys/unseal", handleSysUnseal(core))
mux.Handle("/v1/sys/mounts", handleSysMounts(core)) mux.Handle("/v1/sys/mounts", handleSysListMounts(core))
mux.Handle("/v1/sys/mount/", handleSysMount(core))
mux.Handle("/v1/", handleLogical(core)) mux.Handle("/v1/", handleLogical(core))
return mux return mux
} }

View file

@ -8,7 +8,15 @@ import (
"testing" "testing"
) )
func testHttpPost(t *testing.T, addr string, body interface{}) *http.Response {
return testHttpData(t, "POST", addr, body)
}
func testHttpPut(t *testing.T, addr string, body interface{}) *http.Response { func testHttpPut(t *testing.T, addr string, body interface{}) *http.Response {
return testHttpData(t, "PUT", addr, body)
}
func testHttpData(t *testing.T, method string, addr string, body interface{}) *http.Response {
bodyReader := new(bytes.Buffer) bodyReader := new(bytes.Buffer)
if body != nil { if body != nil {
enc := json.NewEncoder(bodyReader) enc := json.NewEncoder(bodyReader)
@ -17,7 +25,7 @@ func testHttpPut(t *testing.T, addr string, body interface{}) *http.Response {
} }
} }
req, err := http.NewRequest("PUT", addr, bodyReader) req, err := http.NewRequest(method, addr, bodyReader)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }

View file

@ -2,12 +2,13 @@ package http
import ( import (
"net/http" "net/http"
"strings"
"github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
) )
func handleSysMounts(core *vault.Core) http.Handler { func handleSysListMounts(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" { if r.Method != "GET" {
respondError(w, http.StatusMethodNotAllowed, nil) respondError(w, http.StatusMethodNotAllowed, nil)
@ -26,3 +27,51 @@ func handleSysMounts(core *vault.Core) http.Handler {
respondOk(w, resp.Data) respondOk(w, resp.Data)
}) })
} }
func handleSysMount(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
respondError(w, http.StatusMethodNotAllowed, nil)
return
}
// Determine the path...
prefix := "/v1/sys/mount/"
if !strings.HasPrefix(r.URL.Path, prefix) {
respondError(w, http.StatusNotFound, nil)
return
}
path := r.URL.Path[len(prefix):]
if path == "" {
respondError(w, http.StatusNotFound, nil)
return
}
// Parse the request if we can
var req MountRequest
if err := parseRequest(r, &req); err != nil {
respondError(w, http.StatusBadRequest, err)
return
}
_, err := core.HandleRequest(&logical.Request{
Operation: logical.WriteOperation,
Path: "sys/mount/" + path,
Data: map[string]interface{}{
"type": req.Type,
"description": req.Description,
},
})
if err != nil {
respondError(w, http.StatusInternalServerError, err)
return
}
respondOk(w, nil)
})
}
type MountRequest struct {
Type string `json:"type"`
Description string `json:"description"`
}

View file

@ -35,3 +35,41 @@ func TestSysMounts(t *testing.T) {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }
} }
func TestSysMount(t *testing.T) {
core, _ := vault.TestCoreUnsealed(t)
ln, addr := TestServer(t, core)
defer ln.Close()
resp := testHttpPost(t, addr+"/v1/sys/mount/foo", map[string]interface{}{
"type": "generic",
"description": "foo",
})
testResponseStatus(t, resp, 204)
resp, err := http.Get(addr + "/v1/sys/mounts")
if err != nil {
t.Fatalf("err: %s", err)
}
var actual map[string]interface{}
expected := map[string]interface{}{
"foo/": map[string]interface{}{
"description": "foo",
"type": "generic",
},
"secret/": map[string]interface{}{
"description": "generic secret storage",
"type": "generic",
},
"sys/": map[string]interface{}{
"description": "system endpoints used for control, policy and debugging",
"type": "system",
},
}
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}

View file

@ -29,7 +29,7 @@ func NewSystemBackend(core *Core) logical.Backend {
}, },
&framework.Path{ &framework.Path{
Pattern: "mount/(?P<path>.+?)", Pattern: "mount/(?P<path>.+)",
Fields: map[string]*framework.FieldSchema{ Fields: map[string]*framework.FieldSchema{
"path": &framework.FieldSchema{ "path": &framework.FieldSchema{