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  }