github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/state/autopilot.go (about) 1 package state 2 3 import ( 4 "fmt" 5 6 memdb "github.com/hashicorp/go-memdb" 7 "github.com/hashicorp/nomad/nomad/structs" 8 ) 9 10 // autopilotConfigTableSchema returns a new table schema used for storing 11 // the autopilot configuration 12 func autopilotConfigTableSchema() *memdb.TableSchema { 13 return &memdb.TableSchema{ 14 Name: "autopilot-config", 15 Indexes: map[string]*memdb.IndexSchema{ 16 "id": { 17 Name: "id", 18 AllowMissing: true, 19 Unique: true, 20 Indexer: &memdb.ConditionalIndex{ 21 Conditional: func(obj interface{}) (bool, error) { return true, nil }, 22 }, 23 }, 24 }, 25 } 26 } 27 28 // AutopilotConfig is used to get the current Autopilot configuration. 29 func (s *StateStore) AutopilotConfig() (uint64, *structs.AutopilotConfig, error) { 30 tx := s.db.ReadTxn() 31 defer tx.Abort() 32 33 // Get the autopilot config 34 c, err := tx.First("autopilot-config", "id") 35 if err != nil { 36 return 0, nil, fmt.Errorf("failed autopilot config lookup: %s", err) 37 } 38 39 config, ok := c.(*structs.AutopilotConfig) 40 if !ok { 41 return 0, nil, nil 42 } 43 44 return config.ModifyIndex, config, nil 45 } 46 47 // AutopilotSetConfig is used to set the current Autopilot configuration. 48 func (s *StateStore) AutopilotSetConfig(index uint64, config *structs.AutopilotConfig) error { 49 tx := s.db.WriteTxn(index) 50 defer tx.Abort() 51 52 if err := s.autopilotSetConfigTxn(index, tx, config); err != nil { 53 return err 54 } 55 56 return tx.Commit() 57 } 58 59 // AutopilotCASConfig is used to try updating the Autopilot configuration with a 60 // given Raft index. If the CAS index specified is not equal to the last observed index 61 // for the config, then the call is a noop, 62 func (s *StateStore) AutopilotCASConfig(index, cidx uint64, config *structs.AutopilotConfig) (bool, error) { 63 tx := s.db.WriteTxn(index) 64 defer tx.Abort() 65 66 // Check for an existing config 67 existing, err := tx.First("autopilot-config", "id") 68 if err != nil { 69 return false, fmt.Errorf("failed autopilot config lookup: %s", err) 70 } 71 72 // If the existing index does not match the provided CAS 73 // index arg, then we shouldn't update anything and can safely 74 // return early here. 75 e, ok := existing.(*structs.AutopilotConfig) 76 if !ok || e.ModifyIndex != cidx { 77 return false, nil 78 } 79 80 if err := s.autopilotSetConfigTxn(index, tx, config); err != nil { 81 return false, err 82 } 83 84 err = tx.Commit() 85 return err == nil, err 86 } 87 88 func (s *StateStore) autopilotSetConfigTxn(idx uint64, tx *txn, config *structs.AutopilotConfig) error { 89 // Check for an existing config 90 existing, err := tx.First("autopilot-config", "id") 91 if err != nil { 92 return fmt.Errorf("failed autopilot config lookup: %s", err) 93 } 94 95 // Set the indexes. 96 if existing != nil { 97 config.CreateIndex = existing.(*structs.AutopilotConfig).CreateIndex 98 } else { 99 config.CreateIndex = idx 100 } 101 config.ModifyIndex = idx 102 103 if err := tx.Insert("autopilot-config", config); err != nil { 104 return fmt.Errorf("failed updating autopilot config: %s", err) 105 } 106 return nil 107 }