gopkg.in/hashicorp/nomad.v0@v0.11.8/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.Txn(false)
    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(idx uint64, config *structs.AutopilotConfig) error {
    49  	tx := s.db.Txn(true)
    50  	defer tx.Abort()
    51  
    52  	s.autopilotSetConfigTxn(idx, tx, config)
    53  
    54  	tx.Commit()
    55  	return nil
    56  }
    57  
    58  // AutopilotCASConfig is used to try updating the Autopilot configuration with a
    59  // given Raft index. If the CAS index specified is not equal to the last observed index
    60  // for the config, then the call is a noop,
    61  func (s *StateStore) AutopilotCASConfig(idx, cidx uint64, config *structs.AutopilotConfig) (bool, error) {
    62  	tx := s.db.Txn(true)
    63  	defer tx.Abort()
    64  
    65  	// Check for an existing config
    66  	existing, err := tx.First("autopilot-config", "id")
    67  	if err != nil {
    68  		return false, fmt.Errorf("failed autopilot config lookup: %s", err)
    69  	}
    70  
    71  	// If the existing index does not match the provided CAS
    72  	// index arg, then we shouldn't update anything and can safely
    73  	// return early here.
    74  	e, ok := existing.(*structs.AutopilotConfig)
    75  	if !ok || e.ModifyIndex != cidx {
    76  		return false, nil
    77  	}
    78  
    79  	s.autopilotSetConfigTxn(idx, tx, config)
    80  
    81  	tx.Commit()
    82  	return true, nil
    83  }
    84  
    85  func (s *StateStore) autopilotSetConfigTxn(idx uint64, tx *memdb.Txn, config *structs.AutopilotConfig) error {
    86  	// Check for an existing config
    87  	existing, err := tx.First("autopilot-config", "id")
    88  	if err != nil {
    89  		return fmt.Errorf("failed autopilot config lookup: %s", err)
    90  	}
    91  
    92  	// Set the indexes.
    93  	if existing != nil {
    94  		config.CreateIndex = existing.(*structs.AutopilotConfig).CreateIndex
    95  	} else {
    96  		config.CreateIndex = idx
    97  	}
    98  	config.ModifyIndex = idx
    99  
   100  	if err := tx.Insert("autopilot-config", config); err != nil {
   101  		return fmt.Errorf("failed updating autopilot config: %s", err)
   102  	}
   103  	return nil
   104  }