open-consul/consul/internal_endpoint.go

167 lines
4.3 KiB
Go
Raw Normal View History

2014-04-27 19:56:06 +00:00
package consul
import (
2015-07-07 00:28:09 +00:00
"fmt"
2014-04-27 19:56:06 +00:00
"github.com/hashicorp/consul/consul/structs"
"github.com/hashicorp/serf/serf"
2014-04-27 19:56:06 +00:00
)
2014-04-28 21:44:36 +00:00
// Internal endpoint is used to query the miscellaneous info that
2014-04-27 19:56:06 +00:00
// does not necessarily fit into the other systems. It is also
// used to hold undocumented APIs that users should not rely on.
2014-04-28 21:44:36 +00:00
type Internal struct {
2014-04-27 19:56:06 +00:00
srv *Server
}
// NodeInfo is used to retrieve information about a specific node.
2014-04-28 21:44:36 +00:00
func (m *Internal) NodeInfo(args *structs.NodeSpecificRequest,
2014-04-27 19:56:06 +00:00
reply *structs.IndexedNodeDump) error {
2014-04-28 21:44:36 +00:00
if done, err := m.srv.forward("Internal.NodeInfo", args, args, reply); done {
2014-04-27 19:56:06 +00:00
return err
}
// Get the node info
2014-04-27 19:56:06 +00:00
state := m.srv.fsm.State()
return m.srv.blockingRPC(&args.QueryOptions,
&reply.QueryMeta,
state.QueryTables("NodeInfo"),
func() error {
reply.Index, reply.Dump = state.NodeInfo(args.Node)
return m.srv.filterACL(args.Token, reply)
2014-04-27 19:56:06 +00:00
})
}
// NodeDump is used to generate information about all of the nodes.
2014-04-28 21:44:36 +00:00
func (m *Internal) NodeDump(args *structs.DCSpecificRequest,
2014-04-27 19:56:06 +00:00
reply *structs.IndexedNodeDump) error {
2014-04-28 21:44:36 +00:00
if done, err := m.srv.forward("Internal.NodeDump", args, args, reply); done {
2014-04-27 19:56:06 +00:00
return err
}
// Get all the node info
2014-04-27 19:56:06 +00:00
state := m.srv.fsm.State()
return m.srv.blockingRPC(&args.QueryOptions,
&reply.QueryMeta,
state.QueryTables("NodeDump"),
func() error {
reply.Index, reply.Dump = state.NodeDump()
return m.srv.filterACL(args.Token, reply)
2014-04-27 19:56:06 +00:00
})
}
2014-08-28 22:00:49 +00:00
// EventFire is a bit of an odd endpoint, but it allows for a cross-DC RPC
// call to fire an event. The primary use case is to enable user events being
// triggered in a remote DC.
func (m *Internal) EventFire(args *structs.EventFireRequest,
reply *structs.EventFireResponse) error {
if done, err := m.srv.forward("Internal.EventFire", args, args, reply); done {
return err
}
2015-06-18 01:57:17 +00:00
// Check ACLs
acl, err := m.srv.resolveToken(args.Token)
if err != nil {
return err
}
if acl != nil && !acl.EventWrite(args.Name) {
m.srv.logger.Printf("[WARN] consul: user event %q blocked by ACLs", args.Name)
return permissionDeniedErr
}
2014-08-28 22:00:49 +00:00
// Set the query meta data
m.srv.setQueryMeta(&reply.QueryMeta)
// Add the consul prefix to the event name
eventName := userEventName(args.Name)
2014-08-28 22:00:49 +00:00
// Fire the event
return m.srv.serfLAN.UserEvent(eventName, args.Payload, false)
2014-08-28 22:00:49 +00:00
}
// KeyringOperation will query the WAN and LAN gossip keyrings of all nodes.
func (m *Internal) KeyringOperation(
2014-09-25 01:30:34 +00:00
args *structs.KeyringRequest,
reply *structs.KeyringResponses) error {
2015-07-07 00:28:09 +00:00
// Check ACLs
acl, err := m.srv.resolveToken(args.Token)
if err != nil {
return err
}
if acl != nil {
switch args.Operation {
case structs.KeyringList:
if !acl.KeyringRead() {
return fmt.Errorf("Reading keyring denied by ACLs")
}
case structs.KeyringInstall:
fallthrough
case structs.KeyringUse:
fallthrough
case structs.KeyringRemove:
if !acl.KeyringWrite() {
return fmt.Errorf("Modifying keyring denied due to ACLs")
}
default:
panic("Invalid keyring operation")
}
}
// Only perform WAN keyring querying and RPC forwarding once
if !args.Forwarded {
args.Forwarded = true
2014-10-06 22:14:30 +00:00
m.executeKeyringOp(args, reply, true)
return m.srv.globalRPC("Internal.KeyringOperation", args, reply)
}
// Query the LAN keyring of this node's DC
m.executeKeyringOp(args, reply, false)
return nil
}
// executeKeyringOp executes the appropriate keyring-related function based on
// the type of keyring operation in the request. It takes the KeyManager as an
// argument, so it can handle any operation for either LAN or WAN pools.
2014-10-05 20:59:27 +00:00
func (m *Internal) executeKeyringOp(
2014-09-25 01:30:34 +00:00
args *structs.KeyringRequest,
2014-10-05 20:59:27 +00:00
reply *structs.KeyringResponses,
wan bool) {
var serfResp *serf.KeyResponse
var err error
var mgr *serf.KeyManager
2014-10-06 22:14:30 +00:00
2014-10-05 20:59:27 +00:00
if wan {
mgr = m.srv.KeyManagerWAN()
} else {
mgr = m.srv.KeyManagerLAN()
}
switch args.Operation {
case structs.KeyringList:
2014-10-05 20:59:27 +00:00
serfResp, err = mgr.ListKeys()
case structs.KeyringInstall:
2014-10-05 20:59:27 +00:00
serfResp, err = mgr.InstallKey(args.Key)
case structs.KeyringUse:
2014-10-05 20:59:27 +00:00
serfResp, err = mgr.UseKey(args.Key)
case structs.KeyringRemove:
2014-10-05 20:59:27 +00:00
serfResp, err = mgr.RemoveKey(args.Key)
}
errStr := ""
if err != nil {
errStr = err.Error()
}
reply.Responses = append(reply.Responses, &structs.KeyringResponse{
WAN: wan,
2014-10-06 22:14:30 +00:00
Datacenter: m.srv.config.Datacenter,
Messages: serfResp.Messages,
Keys: serfResp.Keys,
NumNodes: serfResp.NumNodes,
Error: errStr,
})
}