2023-05-15 14:49:08 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
memdb "github.com/hashicorp/go-memdb"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
|
|
|
// nodePoolInit creates the built-in node pools that should always be present
|
|
|
|
// in the cluster.
|
|
|
|
func (s *StateStore) nodePoolInit() error {
|
|
|
|
allNodePool := &structs.NodePool{
|
|
|
|
Name: structs.NodePoolAll,
|
|
|
|
Description: structs.NodePoolAllDescription,
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultNodePool := &structs.NodePool{
|
|
|
|
Name: structs.NodePoolDefault,
|
|
|
|
Description: structs.NodePoolDefaultDescription,
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.UpsertNodePools(
|
2023-06-06 14:14:47 +00:00
|
|
|
structs.SystemInitializationType,
|
2023-05-15 14:49:08 +00:00
|
|
|
1,
|
|
|
|
[]*structs.NodePool{allNodePool, defaultNodePool},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodePools returns an iterator over all node pools.
|
2023-06-01 19:55:49 +00:00
|
|
|
func (s *StateStore) NodePools(ws memdb.WatchSet, sort SortOption) (memdb.ResultIterator, error) {
|
2023-05-15 14:49:08 +00:00
|
|
|
txn := s.db.ReadTxn()
|
|
|
|
|
2023-06-01 19:55:49 +00:00
|
|
|
var iter memdb.ResultIterator
|
|
|
|
var err error
|
|
|
|
|
|
|
|
switch sort {
|
|
|
|
case SortReverse:
|
|
|
|
iter, err = txn.GetReverse(TableNodePools, "id")
|
|
|
|
default:
|
|
|
|
iter, err = txn.Get(TableNodePools, "id")
|
|
|
|
}
|
2023-05-15 14:49:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("node pools lookup failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ws.Add(iter.WatchCh())
|
|
|
|
return iter, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodePoolByName returns the node pool that matches the given name or nil if
|
|
|
|
// there is no match.
|
|
|
|
func (s *StateStore) NodePoolByName(ws memdb.WatchSet, name string) (*structs.NodePool, error) {
|
|
|
|
txn := s.db.ReadTxn()
|
2023-06-02 21:50:50 +00:00
|
|
|
return s.nodePoolByNameTxn(txn, ws, name)
|
|
|
|
}
|
2023-05-15 14:49:08 +00:00
|
|
|
|
2023-06-02 21:50:50 +00:00
|
|
|
func (s *StateStore) nodePoolByNameTxn(txn *txn, ws memdb.WatchSet, name string) (*structs.NodePool, error) {
|
2023-05-15 14:49:08 +00:00
|
|
|
watchCh, existing, err := txn.FirstWatch(TableNodePools, "id", name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("node pool lookup failed: %w", err)
|
|
|
|
}
|
|
|
|
ws.Add(watchCh)
|
|
|
|
|
|
|
|
if existing == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return existing.(*structs.NodePool), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodePoolsByNamePrefix returns an interator over all node pools that match
|
|
|
|
// the given name prefix.
|
2023-06-01 19:55:49 +00:00
|
|
|
func (s *StateStore) NodePoolsByNamePrefix(ws memdb.WatchSet, namePrefix string, sort SortOption) (memdb.ResultIterator, error) {
|
2023-05-15 14:49:08 +00:00
|
|
|
txn := s.db.ReadTxn()
|
|
|
|
|
2023-06-01 19:55:49 +00:00
|
|
|
var iter memdb.ResultIterator
|
|
|
|
var err error
|
|
|
|
|
|
|
|
switch sort {
|
|
|
|
case SortReverse:
|
|
|
|
iter, err = txn.GetReverse(TableNodePools, "id_prefix", namePrefix)
|
|
|
|
default:
|
|
|
|
iter, err = txn.Get(TableNodePools, "id_prefix", namePrefix)
|
|
|
|
}
|
2023-05-15 14:49:08 +00:00
|
|
|
if err != nil {
|
2023-06-01 19:55:49 +00:00
|
|
|
return nil, fmt.Errorf("node pools prefix lookup failed: %w", err)
|
2023-05-15 14:49:08 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 19:55:49 +00:00
|
|
|
ws.Add(iter.WatchCh())
|
2023-05-15 14:49:08 +00:00
|
|
|
return iter, nil
|
|
|
|
}
|
|
|
|
|
2023-06-16 20:30:22 +00:00
|
|
|
// nodePoolExists returs true if a node pool with the give name exists.
|
|
|
|
func (s *StateStore) nodePoolExists(txn *txn, pool string) (bool, error) {
|
|
|
|
existing, err := txn.First(TableNodePools, "id", pool)
|
|
|
|
return existing != nil, err
|
|
|
|
}
|
|
|
|
|
2023-05-15 14:49:08 +00:00
|
|
|
// UpsertNodePools inserts or updates the given set of node pools.
|
|
|
|
func (s *StateStore) UpsertNodePools(msgType structs.MessageType, index uint64, pools []*structs.NodePool) error {
|
|
|
|
txn := s.db.WriteTxnMsgT(msgType, index)
|
|
|
|
defer txn.Abort()
|
|
|
|
|
|
|
|
for _, pool := range pools {
|
|
|
|
if err := s.upsertNodePoolTxn(txn, index, pool); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := txn.Insert("index", &IndexEntry{TableNodePools, index}); err != nil {
|
|
|
|
return fmt.Errorf("index update failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return txn.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StateStore) upsertNodePoolTxn(txn *txn, index uint64, pool *structs.NodePool) error {
|
|
|
|
if pool == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
existing, err := txn.First(TableNodePools, "id", pool.Name)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("node pool lookup failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if existing != nil {
|
|
|
|
// Prevent changes to built-in node pools.
|
|
|
|
if pool.IsBuiltIn() {
|
|
|
|
return fmt.Errorf("modifying node pool %q is not allowed", pool.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
exist := existing.(*structs.NodePool)
|
|
|
|
pool.CreateIndex = exist.CreateIndex
|
|
|
|
pool.ModifyIndex = index
|
|
|
|
} else {
|
|
|
|
pool.CreateIndex = index
|
|
|
|
pool.ModifyIndex = index
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := txn.Insert(TableNodePools, pool); err != nil {
|
|
|
|
return fmt.Errorf("node pool insert failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-02 21:50:50 +00:00
|
|
|
// fetchOrCreateNodePoolTxn returns an existing node pool with the given name
|
|
|
|
// or creates a new one if it doesn't exist.
|
|
|
|
func (s *StateStore) fetchOrCreateNodePoolTxn(txn *txn, index uint64, name string) (*structs.NodePool, error) {
|
|
|
|
pool, err := s.nodePoolByNameTxn(txn, nil, name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if pool == nil {
|
|
|
|
pool = &structs.NodePool{Name: name}
|
|
|
|
err = s.upsertNodePoolTxn(txn, index, pool)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pool, nil
|
|
|
|
}
|
|
|
|
|
2023-05-15 14:49:08 +00:00
|
|
|
// DeleteNodePools removes the given set of node pools.
|
|
|
|
func (s *StateStore) DeleteNodePools(msgType structs.MessageType, index uint64, names []string) error {
|
|
|
|
txn := s.db.WriteTxnMsgT(msgType, index)
|
|
|
|
defer txn.Abort()
|
|
|
|
|
|
|
|
for _, n := range names {
|
|
|
|
if err := s.deleteNodePoolTxn(txn, index, n); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update index table.
|
|
|
|
if err := txn.Insert("index", &IndexEntry{TableNodePools, index}); err != nil {
|
|
|
|
return fmt.Errorf("index update failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return txn.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *StateStore) deleteNodePoolTxn(txn *txn, index uint64, name string) error {
|
|
|
|
// Check if node pool exists.
|
|
|
|
existing, err := txn.First(TableNodePools, "id", name)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("node pool lookup failed: %w", err)
|
|
|
|
}
|
|
|
|
if existing == nil {
|
|
|
|
return fmt.Errorf("node pool %s not found", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
pool := existing.(*structs.NodePool)
|
|
|
|
|
|
|
|
// Prevent deletion of built-in node pools.
|
|
|
|
if pool.IsBuiltIn() {
|
|
|
|
return fmt.Errorf("deleting node pool %q is not allowed", pool.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete node pool.
|
|
|
|
if err := txn.Delete(TableNodePools, pool); err != nil {
|
|
|
|
return fmt.Errorf("node pool deletion failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|