Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6e51251
consul: Adding new directory structs for KVS
armon Mar 31, 2014
a365b30
consul: Adding kvs table to state store
armon Mar 31, 2014
a6086e1
consul: Adding KVSDeleteTree operation
armon Mar 31, 2014
6744ee6
consul: Implement and test KV get and set
armon Mar 31, 2014
f87c474
consul: Implement KVSDelete
armon Mar 31, 2014
8d7c5fc
consul: Implementing Check-And-Set
armon Mar 31, 2014
59703cb
consul: Adding support for virtual indexes
armon Mar 31, 2014
dfb8c03
consul: Adding support for KVSList
armon Mar 31, 2014
860cfd7
consul: Support DeleteTree
armon Mar 31, 2014
9cfea72
consul: Snapshot KVS store support
armon Mar 31, 2014
f91e12f
consul: Adding FSM support for KVS operations
armon Mar 31, 2014
c31232f
consul: FSM support to snapshot/restore KVS values
armon Mar 31, 2014
6ca5c7c
consul: Testing FSM application of KVS commands
armon Mar 31, 2014
47ad40a
consul: Adding KVS RPC endpoint
armon Mar 31, 2014
3e9dc6d
consul: First pass at KVS endpoints for RPC
armon Mar 31, 2014
fc51104
consul: Adding tests for endpoint method
armon Mar 31, 2014
1b2dd17
consul: Test the remaining KVS endpoints
armon Mar 31, 2014
6cfde2b
agent: First pass at KVS endpoints
armon Apr 1, 2014
94df059
consul: Enable a recursive delete of all keys
armon Apr 1, 2014
ceb6964
consul: Return 404 if no entries found
armon Apr 1, 2014
ca1c2d7
agnet: Fix parsing of cas flag
armon Apr 1, 2014
8f2ef0d
consul: Fixing blocking query if set table is at index 0
armon Apr 1, 2014
512c689
consul: Adding raft endpoint to force a snapshot
armon Apr 1, 2014
526629e
agent: Adding tests for the KV endpoints
armon Apr 1, 2014
f7e7696
website: Update format of consul info
armon Apr 1, 2014
cfa4ba2
website: Document the Key/Value API
armon Apr 1, 2014
4ccb2d4
consul: More efficient restore of KVS entriesg
armon Apr 1, 2014
8172526
consul: Support a streaming transaction
armon Apr 1, 2014
9473bbe
consul: Avoid loading all KV pairs during a snapshot
armon Apr 1, 2014
5ff482d
consul: FSM snapshot can avoid type assertion
armon Apr 1, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions command/agent/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) {
s.mux.HandleFunc("/v1/agent/service/register", s.wrap(s.AgentRegisterService))
s.mux.HandleFunc("/v1/agent/service/deregister", s.wrap(s.AgentDeregisterService))

s.mux.HandleFunc("/v1/kv/", s.wrap(s.KVSEndpoint))

if enableDebug {
s.mux.HandleFunc("/debug/pprof/", pprof.Index)
s.mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
Expand Down
9 changes: 8 additions & 1 deletion command/agent/http_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ register new services.
The URLs are also versioned to allow for changes in the API.
The current URLs supported are:

Catalog:
* /v1/catalog/register : Registers a new service
* /v1/catalog/deregister : Deregisters a service or node
* /v1/catalog/datacenters : Lists known datacenters
Expand All @@ -16,15 +17,17 @@ The current URLs supported are:
* /v1/catalog/service/<service>/ : Lists the nodes in a given service
* /v1/catalog/node/<node>/ : Lists the services provided by a node

* Health system:
Health system:
* /v1/health/node/<node>: Returns the health info of a node
* /v1/health/checks/<service>: Returns the checks of a service
* /v1/health/service/<service>: Returns the nodes and health info of a service
* /v1/health/state/<state>: Returns the checks in a given state

Status:
* /v1/status/leader : Returns the current Raft leader
* /v1/status/peers : Returns the current Raft peer set

Agent:
* /v1/agent/checks: Returns the checks the local agent is managing
* /v1/agent/services : Returns the services local agent is managing
* /v1/agent/members : Returns the members as seen by the local serf agent
Expand All @@ -37,3 +40,7 @@ The current URLs supported are:
* /v1/agent/check/fail/<name>
* /v1/agent/service/register
* /v1/agent/service/deregister/<name>

KVS:
* /v1/kv/<key>

153 changes: 153 additions & 0 deletions command/agent/kvs_endpoint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package agent

import (
"bytes"
"github.com/hashicorp/consul/consul/structs"
"io"
"net/http"
"strconv"
"strings"
)

func (s *HTTPServer) KVSEndpoint(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
// Set default DC
args := structs.KeyRequest{}
if done := s.parse(resp, req, &args.Datacenter, &args.BlockingQuery); done {
return nil, nil
}

// Pull out the key name, validation left to each sub-handler
args.Key = strings.TrimPrefix(req.URL.Path, "/v1/kv/")

// Switch on the method
switch req.Method {
case "GET":
return s.KVSGet(resp, req, &args)
case "PUT":
return s.KVSPut(resp, req, &args)
case "DELETE":
return s.KVSDelete(resp, req, &args)
default:
resp.WriteHeader(405)
return nil, nil
}
return nil, nil
}

// KVSGet handles a GET request
func (s *HTTPServer) KVSGet(resp http.ResponseWriter, req *http.Request, args *structs.KeyRequest) (interface{}, error) {
// Check for recurse
method := "KVS.Get"
params := req.URL.Query()
if _, ok := params["recurse"]; ok {
method = "KVS.List"
} else if missingKey(resp, args) {
return nil, nil
}

// Make the RPC
var out structs.IndexedDirEntries
if err := s.agent.RPC(method, &args, &out); err != nil {
return nil, err
}
setIndex(resp, out.Index)

// Check if we get a not found
if len(out.Entries) == 0 {
resp.WriteHeader(404)
return nil, nil
}
return out.Entries, nil
}

// KVSPut handles a PUT request
func (s *HTTPServer) KVSPut(resp http.ResponseWriter, req *http.Request, args *structs.KeyRequest) (interface{}, error) {
if missingKey(resp, args) {
return nil, nil
}
applyReq := structs.KVSRequest{
Datacenter: args.Datacenter,
Op: structs.KVSSet,
DirEnt: structs.DirEntry{
Key: args.Key,
Flags: 0,
Value: nil,
},
}

// Check for flags
params := req.URL.Query()
if _, ok := params["flags"]; ok {
flagVal, err := strconv.ParseUint(params.Get("flags"), 10, 64)
if err != nil {
return nil, err
}
applyReq.DirEnt.Flags = flagVal
}

// Check for cas value
if _, ok := params["cas"]; ok {
casVal, err := strconv.ParseUint(params.Get("cas"), 10, 64)
if err != nil {
return nil, err
}
applyReq.DirEnt.ModifyIndex = casVal
applyReq.Op = structs.KVSCAS
}

// Copy the value
buf := bytes.NewBuffer(nil)
if _, err := io.Copy(buf, req.Body); err != nil {
return nil, err
}
applyReq.DirEnt.Value = buf.Bytes()

// Make the RPC
var out bool
if err := s.agent.RPC("KVS.Apply", &applyReq, &out); err != nil {
return nil, err
}

// Only use the out value if this was a CAS
if applyReq.Op == structs.KVSSet {
return true, nil
} else {
return out, nil
}
}

// KVSPut handles a DELETE request
func (s *HTTPServer) KVSDelete(resp http.ResponseWriter, req *http.Request, args *structs.KeyRequest) (interface{}, error) {
applyReq := structs.KVSRequest{
Datacenter: args.Datacenter,
Op: structs.KVSDelete,
DirEnt: structs.DirEntry{
Key: args.Key,
},
}

// Check for recurse
params := req.URL.Query()
if _, ok := params["recurse"]; ok {
applyReq.Op = structs.KVSDeleteTree
} else if missingKey(resp, args) {
return nil, nil
}

// Make the RPC
var out bool
if err := s.agent.RPC("KVS.Apply", &applyReq, &out); err != nil {
return nil, err
}
return nil, nil
}

// missingKey checks if the key is missing
func missingKey(resp http.ResponseWriter, args *structs.KeyRequest) bool {
if args.Key == "" {
resp.WriteHeader(400)
resp.Write([]byte("Missing key name"))
return true
}
return false
}
Loading