github.com/clly/consul@v1.4.5/agent/consul/fsm/commands_oss.go (about)

     1  package fsm
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/armon/go-metrics"
     8  	"github.com/hashicorp/consul/agent/structs"
     9  	"github.com/hashicorp/consul/api"
    10  )
    11  
    12  func init() {
    13  	registerCommand(structs.RegisterRequestType, (*FSM).applyRegister)
    14  	registerCommand(structs.DeregisterRequestType, (*FSM).applyDeregister)
    15  	registerCommand(structs.KVSRequestType, (*FSM).applyKVSOperation)
    16  	registerCommand(structs.SessionRequestType, (*FSM).applySessionOperation)
    17  	// DEPRECATED (ACL-Legacy-Compat) - Only needed for v1 ACL compat
    18  	registerCommand(structs.ACLRequestType, (*FSM).applyACLOperation)
    19  	registerCommand(structs.TombstoneRequestType, (*FSM).applyTombstoneOperation)
    20  	registerCommand(structs.CoordinateBatchUpdateType, (*FSM).applyCoordinateBatchUpdate)
    21  	registerCommand(structs.PreparedQueryRequestType, (*FSM).applyPreparedQueryOperation)
    22  	registerCommand(structs.TxnRequestType, (*FSM).applyTxn)
    23  	registerCommand(structs.AutopilotRequestType, (*FSM).applyAutopilotUpdate)
    24  	registerCommand(structs.IntentionRequestType, (*FSM).applyIntentionOperation)
    25  	registerCommand(structs.ConnectCARequestType, (*FSM).applyConnectCAOperation)
    26  	registerCommand(structs.ACLTokenSetRequestType, (*FSM).applyACLTokenSetOperation)
    27  	registerCommand(structs.ACLTokenDeleteRequestType, (*FSM).applyACLTokenDeleteOperation)
    28  	registerCommand(structs.ACLBootstrapRequestType, (*FSM).applyACLTokenBootstrap)
    29  	registerCommand(structs.ACLPolicySetRequestType, (*FSM).applyACLPolicySetOperation)
    30  	registerCommand(structs.ACLPolicyDeleteRequestType, (*FSM).applyACLPolicyDeleteOperation)
    31  	registerCommand(structs.ConnectCALeafRequestType, (*FSM).applyConnectCALeafOperation)
    32  }
    33  
    34  func (c *FSM) applyRegister(buf []byte, index uint64) interface{} {
    35  	defer metrics.MeasureSince([]string{"fsm", "register"}, time.Now())
    36  	var req structs.RegisterRequest
    37  	if err := structs.Decode(buf, &req); err != nil {
    38  		panic(fmt.Errorf("failed to decode request: %v", err))
    39  	}
    40  
    41  	// Apply all updates in a single transaction
    42  	if err := c.state.EnsureRegistration(index, &req); err != nil {
    43  		c.logger.Printf("[WARN] consul.fsm: EnsureRegistration failed: %v", err)
    44  		return err
    45  	}
    46  	return nil
    47  }
    48  
    49  func (c *FSM) applyDeregister(buf []byte, index uint64) interface{} {
    50  	defer metrics.MeasureSince([]string{"fsm", "deregister"}, time.Now())
    51  	var req structs.DeregisterRequest
    52  	if err := structs.Decode(buf, &req); err != nil {
    53  		panic(fmt.Errorf("failed to decode request: %v", err))
    54  	}
    55  
    56  	// Either remove the service entry or the whole node. The precedence
    57  	// here is also baked into vetDeregisterWithACL() in acl.go, so if you
    58  	// make changes here, be sure to also adjust the code over there.
    59  	if req.ServiceID != "" {
    60  		if err := c.state.DeleteService(index, req.Node, req.ServiceID); err != nil {
    61  			c.logger.Printf("[WARN] consul.fsm: DeleteNodeService failed: %v", err)
    62  			return err
    63  		}
    64  	} else if req.CheckID != "" {
    65  		if err := c.state.DeleteCheck(index, req.Node, req.CheckID); err != nil {
    66  			c.logger.Printf("[WARN] consul.fsm: DeleteNodeCheck failed: %v", err)
    67  			return err
    68  		}
    69  	} else {
    70  		if err := c.state.DeleteNode(index, req.Node); err != nil {
    71  			c.logger.Printf("[WARN] consul.fsm: DeleteNode failed: %v", err)
    72  			return err
    73  		}
    74  	}
    75  	return nil
    76  }
    77  
    78  func (c *FSM) applyKVSOperation(buf []byte, index uint64) interface{} {
    79  	var req structs.KVSRequest
    80  	if err := structs.Decode(buf, &req); err != nil {
    81  		panic(fmt.Errorf("failed to decode request: %v", err))
    82  	}
    83  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "kvs"}, time.Now(),
    84  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
    85  	switch req.Op {
    86  	case api.KVSet:
    87  		return c.state.KVSSet(index, &req.DirEnt)
    88  	case api.KVDelete:
    89  		return c.state.KVSDelete(index, req.DirEnt.Key)
    90  	case api.KVDeleteCAS:
    91  		act, err := c.state.KVSDeleteCAS(index, req.DirEnt.ModifyIndex, req.DirEnt.Key)
    92  		if err != nil {
    93  			return err
    94  		}
    95  		return act
    96  	case api.KVDeleteTree:
    97  		return c.state.KVSDeleteTree(index, req.DirEnt.Key)
    98  	case api.KVCAS:
    99  		act, err := c.state.KVSSetCAS(index, &req.DirEnt)
   100  		if err != nil {
   101  			return err
   102  		}
   103  		return act
   104  	case api.KVLock:
   105  		act, err := c.state.KVSLock(index, &req.DirEnt)
   106  		if err != nil {
   107  			return err
   108  		}
   109  		return act
   110  	case api.KVUnlock:
   111  		act, err := c.state.KVSUnlock(index, &req.DirEnt)
   112  		if err != nil {
   113  			return err
   114  		}
   115  		return act
   116  	default:
   117  		err := fmt.Errorf("Invalid KVS operation '%s'", req.Op)
   118  		c.logger.Printf("[WARN] consul.fsm: %v", err)
   119  		return err
   120  	}
   121  }
   122  
   123  func (c *FSM) applySessionOperation(buf []byte, index uint64) interface{} {
   124  	var req structs.SessionRequest
   125  	if err := structs.Decode(buf, &req); err != nil {
   126  		panic(fmt.Errorf("failed to decode request: %v", err))
   127  	}
   128  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "session"}, time.Now(),
   129  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   130  	switch req.Op {
   131  	case structs.SessionCreate:
   132  		if err := c.state.SessionCreate(index, &req.Session); err != nil {
   133  			return err
   134  		}
   135  		return req.Session.ID
   136  	case structs.SessionDestroy:
   137  		return c.state.SessionDestroy(index, req.Session.ID)
   138  	default:
   139  		c.logger.Printf("[WARN] consul.fsm: Invalid Session operation '%s'", req.Op)
   140  		return fmt.Errorf("Invalid Session operation '%s'", req.Op)
   141  	}
   142  }
   143  
   144  // DEPRECATED (ACL-Legacy-Compat) - Only needed for legacy compat
   145  func (c *FSM) applyACLOperation(buf []byte, index uint64) interface{} {
   146  	// TODO (ACL-Legacy-Compat) - Should we warn here somehow about using deprecated features
   147  	//                            maybe emit a second metric?
   148  	var req structs.ACLRequest
   149  	if err := structs.Decode(buf, &req); err != nil {
   150  		panic(fmt.Errorf("failed to decode request: %v", err))
   151  	}
   152  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl"}, time.Now(),
   153  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   154  	switch req.Op {
   155  	case structs.ACLBootstrapInit:
   156  		enabled, _, err := c.state.CanBootstrapACLToken()
   157  		if err != nil {
   158  			return err
   159  		}
   160  		return enabled
   161  	case structs.ACLBootstrapNow:
   162  		// This is a bootstrap request from a non-upgraded node
   163  		if err := c.state.ACLBootstrap(index, 0, req.ACL.Convert(), true); err != nil {
   164  			return err
   165  		}
   166  
   167  		if _, token, err := c.state.ACLTokenGetBySecret(nil, req.ACL.ID); err != nil {
   168  			return err
   169  		} else {
   170  			acl, err := token.Convert()
   171  			if err != nil {
   172  				return err
   173  			}
   174  			return acl
   175  		}
   176  
   177  	case structs.ACLForceSet, structs.ACLSet:
   178  		if err := c.state.ACLTokenSet(index, req.ACL.Convert(), true); err != nil {
   179  			return err
   180  		}
   181  		return req.ACL.ID
   182  	case structs.ACLDelete:
   183  		return c.state.ACLTokenDeleteBySecret(index, req.ACL.ID)
   184  	default:
   185  		c.logger.Printf("[WARN] consul.fsm: Invalid ACL operation '%s'", req.Op)
   186  		return fmt.Errorf("Invalid ACL operation '%s'", req.Op)
   187  	}
   188  }
   189  
   190  func (c *FSM) applyTombstoneOperation(buf []byte, index uint64) interface{} {
   191  	var req structs.TombstoneRequest
   192  	if err := structs.Decode(buf, &req); err != nil {
   193  		panic(fmt.Errorf("failed to decode request: %v", err))
   194  	}
   195  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "tombstone"}, time.Now(),
   196  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   197  	switch req.Op {
   198  	case structs.TombstoneReap:
   199  		return c.state.ReapTombstones(req.ReapIndex)
   200  	default:
   201  		c.logger.Printf("[WARN] consul.fsm: Invalid Tombstone operation '%s'", req.Op)
   202  		return fmt.Errorf("Invalid Tombstone operation '%s'", req.Op)
   203  	}
   204  }
   205  
   206  // applyCoordinateBatchUpdate processes a batch of coordinate updates and applies
   207  // them in a single underlying transaction. This interface isn't 1:1 with the outer
   208  // update interface that the coordinate endpoint exposes, so we made it single
   209  // purpose and avoided the opcode convention.
   210  func (c *FSM) applyCoordinateBatchUpdate(buf []byte, index uint64) interface{} {
   211  	var updates structs.Coordinates
   212  	if err := structs.Decode(buf, &updates); err != nil {
   213  		panic(fmt.Errorf("failed to decode batch updates: %v", err))
   214  	}
   215  	defer metrics.MeasureSince([]string{"fsm", "coordinate", "batch-update"}, time.Now())
   216  	if err := c.state.CoordinateBatchUpdate(index, updates); err != nil {
   217  		return err
   218  	}
   219  	return nil
   220  }
   221  
   222  // applyPreparedQueryOperation applies the given prepared query operation to the
   223  // state store.
   224  func (c *FSM) applyPreparedQueryOperation(buf []byte, index uint64) interface{} {
   225  	var req structs.PreparedQueryRequest
   226  	if err := structs.Decode(buf, &req); err != nil {
   227  		panic(fmt.Errorf("failed to decode request: %v", err))
   228  	}
   229  
   230  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "prepared-query"}, time.Now(),
   231  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   232  	switch req.Op {
   233  	case structs.PreparedQueryCreate, structs.PreparedQueryUpdate:
   234  		return c.state.PreparedQuerySet(index, req.Query)
   235  	case structs.PreparedQueryDelete:
   236  		return c.state.PreparedQueryDelete(index, req.Query.ID)
   237  	default:
   238  		c.logger.Printf("[WARN] consul.fsm: Invalid PreparedQuery operation '%s'", req.Op)
   239  		return fmt.Errorf("Invalid PreparedQuery operation '%s'", req.Op)
   240  	}
   241  }
   242  
   243  func (c *FSM) applyTxn(buf []byte, index uint64) interface{} {
   244  	var req structs.TxnRequest
   245  	if err := structs.Decode(buf, &req); err != nil {
   246  		panic(fmt.Errorf("failed to decode request: %v", err))
   247  	}
   248  	defer metrics.MeasureSince([]string{"fsm", "txn"}, time.Now())
   249  	results, errors := c.state.TxnRW(index, req.Ops)
   250  	return structs.TxnResponse{
   251  		Results: results,
   252  		Errors:  errors,
   253  	}
   254  }
   255  
   256  func (c *FSM) applyAutopilotUpdate(buf []byte, index uint64) interface{} {
   257  	var req structs.AutopilotSetConfigRequest
   258  	if err := structs.Decode(buf, &req); err != nil {
   259  		panic(fmt.Errorf("failed to decode request: %v", err))
   260  	}
   261  	defer metrics.MeasureSince([]string{"fsm", "autopilot"}, time.Now())
   262  
   263  	if req.CAS {
   264  		act, err := c.state.AutopilotCASConfig(index, req.Config.ModifyIndex, &req.Config)
   265  		if err != nil {
   266  			return err
   267  		}
   268  		return act
   269  	}
   270  	return c.state.AutopilotSetConfig(index, &req.Config)
   271  }
   272  
   273  // applyIntentionOperation applies the given intention operation to the state store.
   274  func (c *FSM) applyIntentionOperation(buf []byte, index uint64) interface{} {
   275  	var req structs.IntentionRequest
   276  	if err := structs.Decode(buf, &req); err != nil {
   277  		panic(fmt.Errorf("failed to decode request: %v", err))
   278  	}
   279  
   280  	defer metrics.MeasureSinceWithLabels([]string{"consul", "fsm", "intention"}, time.Now(),
   281  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   282  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "intention"}, time.Now(),
   283  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   284  	switch req.Op {
   285  	case structs.IntentionOpCreate, structs.IntentionOpUpdate:
   286  		return c.state.IntentionSet(index, req.Intention)
   287  	case structs.IntentionOpDelete:
   288  		return c.state.IntentionDelete(index, req.Intention.ID)
   289  	default:
   290  		c.logger.Printf("[WARN] consul.fsm: Invalid Intention operation '%s'", req.Op)
   291  		return fmt.Errorf("Invalid Intention operation '%s'", req.Op)
   292  	}
   293  }
   294  
   295  // applyConnectCAOperation applies the given CA operation to the state store.
   296  func (c *FSM) applyConnectCAOperation(buf []byte, index uint64) interface{} {
   297  	var req structs.CARequest
   298  	if err := structs.Decode(buf, &req); err != nil {
   299  		panic(fmt.Errorf("failed to decode request: %v", err))
   300  	}
   301  
   302  	defer metrics.MeasureSinceWithLabels([]string{"consul", "fsm", "ca"}, time.Now(),
   303  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   304  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "ca"}, time.Now(),
   305  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   306  	switch req.Op {
   307  	case structs.CAOpSetConfig:
   308  		if req.Config.ModifyIndex != 0 {
   309  			act, err := c.state.CACheckAndSetConfig(index, req.Config.ModifyIndex, req.Config)
   310  			if err != nil {
   311  				return err
   312  			}
   313  
   314  			return act
   315  		}
   316  
   317  		return c.state.CASetConfig(index, req.Config)
   318  	case structs.CAOpSetRoots:
   319  		act, err := c.state.CARootSetCAS(index, req.Index, req.Roots)
   320  		if err != nil {
   321  			return err
   322  		}
   323  
   324  		return act
   325  	case structs.CAOpSetProviderState:
   326  		act, err := c.state.CASetProviderState(index, req.ProviderState)
   327  		if err != nil {
   328  			return err
   329  		}
   330  
   331  		return act
   332  	case structs.CAOpDeleteProviderState:
   333  		if err := c.state.CADeleteProviderState(req.ProviderState.ID); err != nil {
   334  			return err
   335  		}
   336  
   337  		return true
   338  	case structs.CAOpSetRootsAndConfig:
   339  		act, err := c.state.CARootSetCAS(index, req.Index, req.Roots)
   340  		if err != nil {
   341  			return err
   342  		}
   343  		if !act {
   344  			return act
   345  		}
   346  
   347  		act, err = c.state.CACheckAndSetConfig(index+1, req.Config.ModifyIndex, req.Config)
   348  		if err != nil {
   349  			return err
   350  		}
   351  		return act
   352  	default:
   353  		c.logger.Printf("[WARN] consul.fsm: Invalid CA operation '%s'", req.Op)
   354  		return fmt.Errorf("Invalid CA operation '%s'", req.Op)
   355  	}
   356  }
   357  
   358  func (c *FSM) applyConnectCALeafOperation(buf []byte, index uint64) interface{} {
   359  	var req structs.CALeafRequest
   360  	if err := structs.Decode(buf, &req); err != nil {
   361  		panic(fmt.Errorf("failed to decode request: %v", err))
   362  	}
   363  
   364  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "ca", "leaf"}, time.Now(),
   365  		[]metrics.Label{{Name: "op", Value: string(req.Op)}})
   366  	switch req.Op {
   367  	case structs.CALeafOpIncrementIndex:
   368  		if err := c.state.CALeafSetIndex(index); err != nil {
   369  			return err
   370  		}
   371  		return index
   372  	default:
   373  		c.logger.Printf("[WARN consul.fsm: Invalid CA Leaf operation '%s'", req.Op)
   374  		return fmt.Errorf("Invalid CA operation '%s'", req.Op)
   375  	}
   376  }
   377  
   378  func (c *FSM) applyACLTokenSetOperation(buf []byte, index uint64) interface{} {
   379  	var req structs.ACLTokenBatchSetRequest
   380  	if err := structs.Decode(buf, &req); err != nil {
   381  		panic(fmt.Errorf("failed to decode request: %v", err))
   382  	}
   383  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl", "token"}, time.Now(),
   384  		[]metrics.Label{{Name: "op", Value: "upsert"}})
   385  
   386  	return c.state.ACLTokenBatchSet(index, req.Tokens, req.CAS)
   387  }
   388  
   389  func (c *FSM) applyACLTokenDeleteOperation(buf []byte, index uint64) interface{} {
   390  	var req structs.ACLTokenBatchDeleteRequest
   391  	if err := structs.Decode(buf, &req); err != nil {
   392  		panic(fmt.Errorf("failed to decode request: %v", err))
   393  	}
   394  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl", "token"}, time.Now(),
   395  		[]metrics.Label{{Name: "op", Value: "delete"}})
   396  
   397  	return c.state.ACLTokenBatchDelete(index, req.TokenIDs)
   398  }
   399  
   400  func (c *FSM) applyACLTokenBootstrap(buf []byte, index uint64) interface{} {
   401  	var req structs.ACLTokenBootstrapRequest
   402  	if err := structs.Decode(buf, &req); err != nil {
   403  		panic(fmt.Errorf("failed to decode request: %v", err))
   404  	}
   405  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl", "token"}, time.Now(),
   406  		[]metrics.Label{{Name: "op", Value: "bootstrap"}})
   407  	return c.state.ACLBootstrap(index, req.ResetIndex, &req.Token, false)
   408  }
   409  
   410  func (c *FSM) applyACLPolicySetOperation(buf []byte, index uint64) interface{} {
   411  	var req structs.ACLPolicyBatchSetRequest
   412  	if err := structs.Decode(buf, &req); err != nil {
   413  		panic(fmt.Errorf("failed to decode request: %v", err))
   414  	}
   415  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl", "policy"}, time.Now(),
   416  		[]metrics.Label{{Name: "op", Value: "upsert"}})
   417  
   418  	return c.state.ACLPolicyBatchSet(index, req.Policies)
   419  }
   420  
   421  func (c *FSM) applyACLPolicyDeleteOperation(buf []byte, index uint64) interface{} {
   422  	var req structs.ACLPolicyBatchDeleteRequest
   423  	if err := structs.Decode(buf, &req); err != nil {
   424  		panic(fmt.Errorf("failed to decode request: %v", err))
   425  	}
   426  	defer metrics.MeasureSinceWithLabels([]string{"fsm", "acl", "policy"}, time.Now(),
   427  		[]metrics.Label{{Name: "op", Value: "delete"}})
   428  
   429  	return c.state.ACLPolicyBatchDelete(index, req.PolicyIDs)
   430  }