github.imxd.top/hashicorp/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 }