github.phpd.cn/hashicorp/consul@v1.4.5/agent/consul/internal_endpoint.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/consul/acl"
     7  	"github.com/hashicorp/consul/agent/consul/state"
     8  	"github.com/hashicorp/consul/agent/structs"
     9  	"github.com/hashicorp/go-memdb"
    10  	"github.com/hashicorp/go-multierror"
    11  	"github.com/hashicorp/serf/serf"
    12  )
    13  
    14  // Internal endpoint is used to query the miscellaneous info that
    15  // does not necessarily fit into the other systems. It is also
    16  // used to hold undocumented APIs that users should not rely on.
    17  type Internal struct {
    18  	srv *Server
    19  }
    20  
    21  // NodeInfo is used to retrieve information about a specific node.
    22  func (m *Internal) NodeInfo(args *structs.NodeSpecificRequest,
    23  	reply *structs.IndexedNodeDump) error {
    24  	if done, err := m.srv.forward("Internal.NodeInfo", args, args, reply); done {
    25  		return err
    26  	}
    27  
    28  	return m.srv.blockingQuery(
    29  		&args.QueryOptions,
    30  		&reply.QueryMeta,
    31  		func(ws memdb.WatchSet, state *state.Store) error {
    32  			index, dump, err := state.NodeInfo(ws, args.Node)
    33  			if err != nil {
    34  				return err
    35  			}
    36  
    37  			reply.Index, reply.Dump = index, dump
    38  			return m.srv.filterACL(args.Token, reply)
    39  		})
    40  }
    41  
    42  // NodeDump is used to generate information about all of the nodes.
    43  func (m *Internal) NodeDump(args *structs.DCSpecificRequest,
    44  	reply *structs.IndexedNodeDump) error {
    45  	if done, err := m.srv.forward("Internal.NodeDump", args, args, reply); done {
    46  		return err
    47  	}
    48  
    49  	return m.srv.blockingQuery(
    50  		&args.QueryOptions,
    51  		&reply.QueryMeta,
    52  		func(ws memdb.WatchSet, state *state.Store) error {
    53  			index, dump, err := state.NodeDump(ws)
    54  			if err != nil {
    55  				return err
    56  			}
    57  
    58  			reply.Index, reply.Dump = index, dump
    59  			return m.srv.filterACL(args.Token, reply)
    60  		})
    61  }
    62  
    63  // EventFire is a bit of an odd endpoint, but it allows for a cross-DC RPC
    64  // call to fire an event. The primary use case is to enable user events being
    65  // triggered in a remote DC.
    66  func (m *Internal) EventFire(args *structs.EventFireRequest,
    67  	reply *structs.EventFireResponse) error {
    68  	if done, err := m.srv.forward("Internal.EventFire", args, args, reply); done {
    69  		return err
    70  	}
    71  
    72  	// Check ACLs
    73  	rule, err := m.srv.ResolveToken(args.Token)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	if rule != nil && !rule.EventWrite(args.Name) {
    79  		m.srv.logger.Printf("[WARN] consul: user event %q blocked by ACLs", args.Name)
    80  		return acl.ErrPermissionDenied
    81  	}
    82  
    83  	// Set the query meta data
    84  	m.srv.setQueryMeta(&reply.QueryMeta)
    85  
    86  	// Add the consul prefix to the event name
    87  	eventName := userEventName(args.Name)
    88  
    89  	// Fire the event on all LAN segments
    90  	segments := m.srv.LANSegments()
    91  	var errs error
    92  	for name, segment := range segments {
    93  		err := segment.UserEvent(eventName, args.Payload, false)
    94  		if err != nil {
    95  			err = fmt.Errorf("error broadcasting event to segment %q: %v", name, err)
    96  			errs = multierror.Append(errs, err)
    97  		}
    98  	}
    99  	return errs
   100  }
   101  
   102  // KeyringOperation will query the WAN and LAN gossip keyrings of all nodes.
   103  func (m *Internal) KeyringOperation(
   104  	args *structs.KeyringRequest,
   105  	reply *structs.KeyringResponses) error {
   106  
   107  	// Check ACLs
   108  	rule, err := m.srv.ResolveToken(args.Token)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if rule != nil {
   113  		switch args.Operation {
   114  		case structs.KeyringList:
   115  			if !rule.KeyringRead() {
   116  				return fmt.Errorf("Reading keyring denied by ACLs")
   117  			}
   118  		case structs.KeyringInstall:
   119  			fallthrough
   120  		case structs.KeyringUse:
   121  			fallthrough
   122  		case structs.KeyringRemove:
   123  			if !rule.KeyringWrite() {
   124  				return fmt.Errorf("Modifying keyring denied due to ACLs")
   125  			}
   126  		default:
   127  			panic("Invalid keyring operation")
   128  		}
   129  	}
   130  
   131  	// Only perform WAN keyring querying and RPC forwarding once
   132  	if !args.Forwarded && m.srv.serfWAN != nil {
   133  		args.Forwarded = true
   134  		m.executeKeyringOp(args, reply, true)
   135  		return m.srv.globalRPC("Internal.KeyringOperation", args, reply)
   136  	}
   137  
   138  	// Query the LAN keyring of this node's DC
   139  	m.executeKeyringOp(args, reply, false)
   140  	return nil
   141  }
   142  
   143  // executeKeyringOp executes the keyring-related operation in the request
   144  // on either the WAN or LAN pools.
   145  func (m *Internal) executeKeyringOp(
   146  	args *structs.KeyringRequest,
   147  	reply *structs.KeyringResponses,
   148  	wan bool) {
   149  
   150  	if wan {
   151  		mgr := m.srv.KeyManagerWAN()
   152  		m.executeKeyringOpMgr(mgr, args, reply, wan, "")
   153  	} else {
   154  		segments := m.srv.LANSegments()
   155  		for name, segment := range segments {
   156  			mgr := segment.KeyManager()
   157  			m.executeKeyringOpMgr(mgr, args, reply, wan, name)
   158  		}
   159  	}
   160  }
   161  
   162  // executeKeyringOpMgr executes the appropriate keyring-related function based on
   163  // the type of keyring operation in the request. It takes the KeyManager as an
   164  // argument, so it can handle any operation for either LAN or WAN pools.
   165  func (m *Internal) executeKeyringOpMgr(
   166  	mgr *serf.KeyManager,
   167  	args *structs.KeyringRequest,
   168  	reply *structs.KeyringResponses,
   169  	wan bool,
   170  	segment string) {
   171  	var serfResp *serf.KeyResponse
   172  	var err error
   173  
   174  	opts := &serf.KeyRequestOptions{RelayFactor: args.RelayFactor}
   175  	switch args.Operation {
   176  	case structs.KeyringList:
   177  		serfResp, err = mgr.ListKeysWithOptions(opts)
   178  	case structs.KeyringInstall:
   179  		serfResp, err = mgr.InstallKeyWithOptions(args.Key, opts)
   180  	case structs.KeyringUse:
   181  		serfResp, err = mgr.UseKeyWithOptions(args.Key, opts)
   182  	case structs.KeyringRemove:
   183  		serfResp, err = mgr.RemoveKeyWithOptions(args.Key, opts)
   184  	}
   185  
   186  	errStr := ""
   187  	if err != nil {
   188  		errStr = err.Error()
   189  	}
   190  
   191  	reply.Responses = append(reply.Responses, &structs.KeyringResponse{
   192  		WAN:        wan,
   193  		Datacenter: m.srv.config.Datacenter,
   194  		Segment:    segment,
   195  		Messages:   serfResp.Messages,
   196  		Keys:       serfResp.Keys,
   197  		NumNodes:   serfResp.NumNodes,
   198  		Error:      errStr,
   199  	})
   200  }