Skip to content

Commit

Permalink
Combine keyring endpoints into one
Browse files Browse the repository at this point in the history
  • Loading branch information
kyhavlov committed Nov 23, 2016
1 parent 31453c7 commit 6bd65c6
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 160 deletions.
30 changes: 17 additions & 13 deletions api/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ type RaftConfiguration struct {
Index uint64
}

// KeyringOpts is used for performing Keyring operations
type KeyringOpts struct {
// keyringRequest is used for performing Keyring operations
type keyringRequest struct {
Key string `json:",omitempty"`
}

Expand Down Expand Up @@ -101,9 +101,10 @@ func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) err
}

// KeyringInstall is used to install a new gossip encryption key into the cluster
func (op *Operator) KeyringInstall(key string) error {
r := op.c.newRequest("PUT", "/v1/operator/keyring/install")
r.obj = KeyringOpts{
func (op *Operator) KeyringInstall(key string, q *WriteOptions) error {
r := op.c.newRequest("POST", "/v1/operator/keyring")
r.setWriteOptions(q)
r.obj = keyringRequest{
Key: key,
}
_, resp, err := requireOK(op.c.doRequest(r))
Expand All @@ -115,8 +116,9 @@ func (op *Operator) KeyringInstall(key string) error {
}

// KeyringList is used to list the gossip keys installed in the cluster
func (op *Operator) KeyringList() ([]*KeyringResponse, error) {
r := op.c.newRequest("GET", "/v1/operator/keyring/list")
func (op *Operator) KeyringList(q *QueryOptions) ([]*KeyringResponse, error) {
r := op.c.newRequest("GET", "/v1/operator/keyring")
r.setQueryOptions(q)
_, resp, err := requireOK(op.c.doRequest(r))
if err != nil {
return nil, err
Expand All @@ -131,9 +133,10 @@ func (op *Operator) KeyringList() ([]*KeyringResponse, error) {
}

// KeyringRemove is used to remove a gossip encryption key from the cluster
func (op *Operator) KeyringRemove(key string) error {
r := op.c.newRequest("DELETE", "/v1/operator/keyring/remove")
r.obj = KeyringOpts{
func (op *Operator) KeyringRemove(key string, q *WriteOptions) error {
r := op.c.newRequest("DELETE", "/v1/operator/keyring")
r.setWriteOptions(q)
r.obj = keyringRequest{
Key: key,
}
_, resp, err := requireOK(op.c.doRequest(r))
Expand All @@ -145,9 +148,10 @@ func (op *Operator) KeyringRemove(key string) error {
}

// KeyringUse is used to change the active gossip encryption key
func (op *Operator) KeyringUse(key string) error {
r := op.c.newRequest("PUT", "/v1/operator/keyring/use")
r.obj = KeyringOpts{
func (op *Operator) KeyringUse(key string, q *WriteOptions) error {
r := op.c.newRequest("PUT", "/v1/operator/keyring")
r.setWriteOptions(q)
r.obj = keyringRequest{
Key: key,
}
_, resp, err := requireOK(op.c.doRequest(r))
Expand Down
10 changes: 5 additions & 5 deletions api/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ func TestOperator_KeyringInstallListPutRemove(t *testing.T) {
defer s.Stop()

operator := c.Operator()
if err := operator.KeyringInstall(newKey); err != nil {
if err := operator.KeyringInstall(newKey, nil); err != nil {
t.Fatalf("err: %v", err)
}

listResponses, err := operator.KeyringList()
listResponses, err := operator.KeyringList(nil)
if err != nil {
t.Fatalf("err %v", err)
}
Expand All @@ -75,15 +75,15 @@ func TestOperator_KeyringInstallListPutRemove(t *testing.T) {
}

// Switch the primary to the new key
if err := operator.KeyringUse(newKey); err != nil {
if err := operator.KeyringUse(newKey, nil); err != nil {
t.Fatalf("err: %v", err)
}

if err := operator.KeyringRemove(oldKey); err != nil {
if err := operator.KeyringRemove(oldKey, nil); err != nil {
t.Fatalf("err: %v", err)
}

listResponses, err = operator.KeyringList()
listResponses, err = operator.KeyringList(nil)
if err != nil {
t.Fatalf("err %v", err)
}
Expand Down
5 changes: 1 addition & 4 deletions command/agent/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,7 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) {
s.handleFuncMetrics("/v1/kv/", s.wrap(s.KVSEndpoint))
s.handleFuncMetrics("/v1/operator/raft/configuration", s.wrap(s.OperatorRaftConfiguration))
s.handleFuncMetrics("/v1/operator/raft/peer", s.wrap(s.OperatorRaftPeer))
s.handleFuncMetrics("/v1/operator/keyring/install", s.wrap(s.OperatorKeyringInstall))
s.handleFuncMetrics("/v1/operator/keyring/list", s.wrap(s.OperatorKeyringList))
s.handleFuncMetrics("/v1/operator/keyring/remove", s.wrap(s.OperatorKeyringRemove))
s.handleFuncMetrics("/v1/operator/keyring/use", s.wrap(s.OperatorKeyringUse))
s.handleFuncMetrics("/v1/operator/keyring", s.wrap(s.OperatorKeyringEndpoint))
s.handleFuncMetrics("/v1/query", s.wrap(s.PreparedQueryGeneral))
s.handleFuncMetrics("/v1/query/", s.wrap(s.PreparedQuerySpecific))
s.handleFuncMetrics("/v1/session/create", s.wrap(s.SessionCreate))
Expand Down
123 changes: 50 additions & 73 deletions command/agent/operator_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"

"github.com/hashicorp/consul/consul/structs"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/raft"
)

Expand Down Expand Up @@ -57,109 +58,85 @@ func (s *HTTPServer) OperatorRaftPeer(resp http.ResponseWriter, req *http.Reques
return nil, nil
}

// OperatorKeyringInstall is used to install a new gossip encryption key into the cluster
func (s *HTTPServer) OperatorKeyringInstall(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
if req.Method != "PUT" {
resp.WriteHeader(http.StatusMethodNotAllowed)
return nil, nil
type keyringArgs struct {
Key string
Token string
}

// OperatorKeyringEndpoint handles keyring operations (install, list, use, remove)
func (s *HTTPServer) OperatorKeyringEndpoint(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
var args keyringArgs
if req.Method == "POST" || req.Method == "PUT" || req.Method == "DELETE" {
if err := decodeBody(req, &args, nil); err != nil {
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
return nil, nil
}
}
s.parseToken(req, &args.Token)

var args structs.KeyringRequest
if err := decodeBody(req, &args, nil); err != nil {
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
// Switch on the method
switch req.Method {
case "GET":
return s.KeyringList(resp, req, &args)
case "POST":
return s.KeyringInstall(resp, req, &args)
case "PUT":
return s.KeyringUse(resp, req, &args)
case "DELETE":
return s.KeyringRemove(resp, req, &args)
default:
resp.WriteHeader(405)
return nil, nil
}
s.parseToken(req, &args.Token)
}

// KeyringInstall is used to install a new gossip encryption key into the cluster
func (s *HTTPServer) KeyringInstall(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
responses, err := s.agent.InstallKey(args.Key, args.Token)
if err != nil {
return nil, err
}
for _, response := range responses.Responses {
if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
}

return nil, nil
return nil, keyringErrorsOrNil(responses.Responses)
}

// OperatorKeyringList is used to list the keys installed in the cluster
func (s *HTTPServer) OperatorKeyringList(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
if req.Method != "GET" {
resp.WriteHeader(http.StatusMethodNotAllowed)
return nil, nil
}

var token string
s.parseToken(req, &token)

responses, err := s.agent.ListKeys(token)
// KeyringList is used to list the keys installed in the cluster
func (s *HTTPServer) KeyringList(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
responses, err := s.agent.ListKeys(args.Token)
if err != nil {
return nil, err
}
for _, response := range responses.Responses {
if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
}

return responses.Responses, nil
return responses.Responses, keyringErrorsOrNil(responses.Responses)
}

// OperatorKeyringRemove is used to list the keys installed in the cluster
func (s *HTTPServer) OperatorKeyringRemove(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
if req.Method != "DELETE" {
resp.WriteHeader(http.StatusMethodNotAllowed)
return nil, nil
}

var args structs.KeyringRequest
if err := decodeBody(req, &args, nil); err != nil {
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
return nil, nil
}
s.parseToken(req, &args.Token)

// KeyringRemove is used to list the keys installed in the cluster
func (s *HTTPServer) KeyringRemove(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
responses, err := s.agent.RemoveKey(args.Key, args.Token)
if err != nil {
return nil, err
}
for _, response := range responses.Responses {
if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
}

return nil, nil
return nil, keyringErrorsOrNil(responses.Responses)
}

// OperatorKeyringUse is used to change the primary gossip encryption key
func (s *HTTPServer) OperatorKeyringUse(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
if req.Method != "PUT" {
resp.WriteHeader(http.StatusMethodNotAllowed)
return nil, nil
}

var args structs.KeyringRequest
if err := decodeBody(req, &args, nil); err != nil {
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf("Request decode failed: %v", err)))
return nil, nil
}
s.parseToken(req, &args.Token)

// KeyringUse is used to change the primary gossip encryption key
func (s *HTTPServer) KeyringUse(resp http.ResponseWriter, req *http.Request, args *keyringArgs) (interface{}, error) {
responses, err := s.agent.UseKey(args.Key, args.Token)
if err != nil {
return nil, err
}
for _, response := range responses.Responses {

return nil, keyringErrorsOrNil(responses.Responses)
}

func keyringErrorsOrNil(responses []*structs.KeyringResponse) error {
var errs error
for _, response := range responses {
if response.Error != "" {
return nil, fmt.Errorf(response.Error)
errs = multierror.Append(errs, fmt.Errorf(response.Error))
}
}

return nil, nil
return errs
}
47 changes: 32 additions & 15 deletions command/agent/operator_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ func TestOperator_KeyringInstall(t *testing.T) {
}
httpTestWithConfig(t, func(srv *HTTPServer) {
body := bytes.NewBufferString(fmt.Sprintf("{\"Key\":\"%s\"}", newKey))
req, err := http.NewRequest("PUT", "/v1/operator/keyring/install", body)
req, err := http.NewRequest("POST", "/v1/operator/keyring", body)
if err != nil {
t.Fatalf("err: %v", err)
}

resp := httptest.NewRecorder()
_, err = srv.OperatorKeyringInstall(resp, req)
_, err = srv.OperatorKeyringEndpoint(resp, req)
if err != nil {
t.Fatalf("err: %s", err)
}
Expand All @@ -81,6 +81,9 @@ func TestOperator_KeyringInstall(t *testing.T) {
if err != nil {
t.Fatalf("err: %s", err)
}
if len(listResponse.Responses) != 2 {
t.Fatalf("bad: %d", len(listResponse.Responses))
}

for _, response := range listResponse.Responses {
count, ok := response.Keys[newKey]
Expand All @@ -100,13 +103,13 @@ func TestOperator_KeyringList(t *testing.T) {
c.EncryptKey = key
}
httpTestWithConfig(t, func(srv *HTTPServer) {
req, err := http.NewRequest("GET", "/v1/operator/keyring/list", nil)
req, err := http.NewRequest("GET", "/v1/operator/keyring", nil)
if err != nil {
t.Fatalf("err: %v", err)
}

resp := httptest.NewRecorder()
r, err := srv.OperatorKeyringList(resp, req)
r, err := srv.OperatorKeyringEndpoint(resp, req)
if err != nil {
t.Fatalf("err: %v", err)
}
Expand All @@ -120,13 +123,27 @@ func TestOperator_KeyringList(t *testing.T) {
if len(responses) != 2 {
t.Fatalf("bad: %d", len(responses))
}
for _, response := range responses {
if len(response.Keys) != 1 {
t.Fatalf("bad: %d", len(response.Keys))
}
if _, ok := response.Keys[key]; !ok {
t.Fatalf("bad: %v", ok)
}

// WAN
if len(responses[0].Keys) != 1 {
t.Fatalf("bad: %d", len(responses[0].Keys))
}
if !responses[0].WAN {
t.Fatalf("bad: %v", responses[0].WAN)
}
if _, ok := responses[0].Keys[key]; !ok {
t.Fatalf("bad: %v", ok)
}

// LAN
if len(responses[1].Keys) != 1 {
t.Fatalf("bad: %d", len(responses[1].Keys))
}
if responses[1].WAN {
t.Fatalf("bad: %v", responses[1].WAN)
}
if _, ok := responses[1].Keys[key]; !ok {
t.Fatalf("bad: %v", ok)
}
}, configFunc)
}
Expand Down Expand Up @@ -162,13 +179,13 @@ func TestOperator_KeyringRemove(t *testing.T) {
}

body := bytes.NewBufferString(fmt.Sprintf("{\"Key\":\"%s\"}", tempKey))
req, err := http.NewRequest("DELETE", "/v1/operator/keyring/remove", body)
req, err := http.NewRequest("DELETE", "/v1/operator/keyring", body)
if err != nil {
t.Fatalf("err: %v", err)
}

resp := httptest.NewRecorder()
_, err = srv.OperatorKeyringRemove(resp, req)
_, err = srv.OperatorKeyringEndpoint(resp, req)
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down Expand Up @@ -205,13 +222,13 @@ func TestOperator_KeyringUse(t *testing.T) {
}

body := bytes.NewBufferString(fmt.Sprintf("{\"Key\":\"%s\"}", newKey))
req, err := http.NewRequest("PUT", "/v1/operator/keyring/use", body)
req, err := http.NewRequest("PUT", "/v1/operator/keyring", body)
if err != nil {
t.Fatalf("err: %v", err)
}

resp := httptest.NewRecorder()
_, err = srv.OperatorKeyringUse(resp, req)
_, err = srv.OperatorKeyringEndpoint(resp, req)
if err != nil {
t.Fatalf("err: %s", err)
}
Expand Down
Loading

0 comments on commit 6bd65c6

Please sign in to comment.