github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/nomad/state/schema.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/go-memdb"
     7  	"github.com/hashicorp/nomad/nomad/structs"
     8  )
     9  
    10  // stateStoreSchema is used to return the schema for the state store
    11  func stateStoreSchema() *memdb.DBSchema {
    12  	// Create the root DB schema
    13  	db := &memdb.DBSchema{
    14  		Tables: make(map[string]*memdb.TableSchema),
    15  	}
    16  
    17  	// Collect all the schemas that are needed
    18  	schemas := []func() *memdb.TableSchema{
    19  		indexTableSchema,
    20  		nodeTableSchema,
    21  		jobTableSchema,
    22  		jobSummarySchema,
    23  		periodicLaunchTableSchema,
    24  		evalTableSchema,
    25  		allocTableSchema,
    26  		vaultAccessorTableSchema,
    27  	}
    28  
    29  	// Add each of the tables
    30  	for _, schemaFn := range schemas {
    31  		schema := schemaFn()
    32  		if _, ok := db.Tables[schema.Name]; ok {
    33  			panic(fmt.Sprintf("duplicate table name: %s", schema.Name))
    34  		}
    35  		db.Tables[schema.Name] = schema
    36  	}
    37  	return db
    38  }
    39  
    40  // indexTableSchema is used for
    41  func indexTableSchema() *memdb.TableSchema {
    42  	return &memdb.TableSchema{
    43  		Name: "index",
    44  		Indexes: map[string]*memdb.IndexSchema{
    45  			"id": &memdb.IndexSchema{
    46  				Name:         "id",
    47  				AllowMissing: false,
    48  				Unique:       true,
    49  				Indexer: &memdb.StringFieldIndex{
    50  					Field:     "Key",
    51  					Lowercase: true,
    52  				},
    53  			},
    54  		},
    55  	}
    56  }
    57  
    58  // nodeTableSchema returns the MemDB schema for the nodes table.
    59  // This table is used to store all the client nodes that are registered.
    60  func nodeTableSchema() *memdb.TableSchema {
    61  	return &memdb.TableSchema{
    62  		Name: "nodes",
    63  		Indexes: map[string]*memdb.IndexSchema{
    64  			// Primary index is used for node management
    65  			// and simple direct lookup. ID is required to be
    66  			// unique.
    67  			"id": &memdb.IndexSchema{
    68  				Name:         "id",
    69  				AllowMissing: false,
    70  				Unique:       true,
    71  				Indexer: &memdb.UUIDFieldIndex{
    72  					Field: "ID",
    73  				},
    74  			},
    75  		},
    76  	}
    77  }
    78  
    79  // jobTableSchema returns the MemDB schema for the jobs table.
    80  // This table is used to store all the jobs that have been submitted.
    81  func jobTableSchema() *memdb.TableSchema {
    82  	return &memdb.TableSchema{
    83  		Name: "jobs",
    84  		Indexes: map[string]*memdb.IndexSchema{
    85  			// Primary index is used for job management
    86  			// and simple direct lookup. ID is required to be
    87  			// unique.
    88  			"id": &memdb.IndexSchema{
    89  				Name:         "id",
    90  				AllowMissing: false,
    91  				Unique:       true,
    92  				Indexer: &memdb.StringFieldIndex{
    93  					Field:     "ID",
    94  					Lowercase: true,
    95  				},
    96  			},
    97  			"type": &memdb.IndexSchema{
    98  				Name:         "type",
    99  				AllowMissing: false,
   100  				Unique:       false,
   101  				Indexer: &memdb.StringFieldIndex{
   102  					Field:     "Type",
   103  					Lowercase: false,
   104  				},
   105  			},
   106  			"gc": &memdb.IndexSchema{
   107  				Name:         "gc",
   108  				AllowMissing: false,
   109  				Unique:       false,
   110  				Indexer: &memdb.ConditionalIndex{
   111  					Conditional: jobIsGCable,
   112  				},
   113  			},
   114  			"periodic": &memdb.IndexSchema{
   115  				Name:         "periodic",
   116  				AllowMissing: false,
   117  				Unique:       false,
   118  				Indexer: &memdb.ConditionalIndex{
   119  					Conditional: jobIsPeriodic,
   120  				},
   121  			},
   122  		},
   123  	}
   124  }
   125  
   126  // jobSummarySchema returns the memdb schema for the job summary table
   127  func jobSummarySchema() *memdb.TableSchema {
   128  	return &memdb.TableSchema{
   129  		Name: "job_summary",
   130  		Indexes: map[string]*memdb.IndexSchema{
   131  			"id": &memdb.IndexSchema{
   132  				Name:         "id",
   133  				AllowMissing: false,
   134  				Unique:       true,
   135  				Indexer: &memdb.StringFieldIndex{
   136  					Field:     "JobID",
   137  					Lowercase: true,
   138  				},
   139  			},
   140  		},
   141  	}
   142  }
   143  
   144  // jobIsGCable satisfies the ConditionalIndexFunc interface and creates an index
   145  // on whether a job is eligible for garbage collection.
   146  func jobIsGCable(obj interface{}) (bool, error) {
   147  	j, ok := obj.(*structs.Job)
   148  	if !ok {
   149  		return false, fmt.Errorf("Unexpected type: %v", obj)
   150  	}
   151  
   152  	// The job is GCable if it is batch and it is not periodic
   153  	periodic := j.Periodic != nil && j.Periodic.Enabled
   154  	gcable := j.Type == structs.JobTypeBatch && !periodic
   155  	return gcable, nil
   156  }
   157  
   158  // jobIsPeriodic satisfies the ConditionalIndexFunc interface and creates an index
   159  // on whether a job is periodic.
   160  func jobIsPeriodic(obj interface{}) (bool, error) {
   161  	j, ok := obj.(*structs.Job)
   162  	if !ok {
   163  		return false, fmt.Errorf("Unexpected type: %v", obj)
   164  	}
   165  
   166  	if j.Periodic != nil && j.Periodic.Enabled == true {
   167  		return true, nil
   168  	}
   169  
   170  	return false, nil
   171  }
   172  
   173  // periodicLaunchTableSchema returns the MemDB schema tracking the most recent
   174  // launch time for a perioidic job.
   175  func periodicLaunchTableSchema() *memdb.TableSchema {
   176  	return &memdb.TableSchema{
   177  		Name: "periodic_launch",
   178  		Indexes: map[string]*memdb.IndexSchema{
   179  			// Primary index is used for job management
   180  			// and simple direct lookup. ID is required to be
   181  			// unique.
   182  			"id": &memdb.IndexSchema{
   183  				Name:         "id",
   184  				AllowMissing: false,
   185  				Unique:       true,
   186  				Indexer: &memdb.StringFieldIndex{
   187  					Field:     "ID",
   188  					Lowercase: true,
   189  				},
   190  			},
   191  		},
   192  	}
   193  }
   194  
   195  // evalTableSchema returns the MemDB schema for the eval table.
   196  // This table is used to store all the evaluations that are pending
   197  // or recently completed.
   198  func evalTableSchema() *memdb.TableSchema {
   199  	return &memdb.TableSchema{
   200  		Name: "evals",
   201  		Indexes: map[string]*memdb.IndexSchema{
   202  			// Primary index is used for direct lookup.
   203  			"id": &memdb.IndexSchema{
   204  				Name:         "id",
   205  				AllowMissing: false,
   206  				Unique:       true,
   207  				Indexer: &memdb.UUIDFieldIndex{
   208  					Field: "ID",
   209  				},
   210  			},
   211  
   212  			// Job index is used to lookup allocations by job
   213  			"job": &memdb.IndexSchema{
   214  				Name:         "job",
   215  				AllowMissing: false,
   216  				Unique:       false,
   217  				Indexer: &memdb.StringFieldIndex{
   218  					Field:     "JobID",
   219  					Lowercase: true,
   220  				},
   221  			},
   222  		},
   223  	}
   224  }
   225  
   226  // allocTableSchema returns the MemDB schema for the allocation table.
   227  // This table is used to store all the task allocations between task groups
   228  // and nodes.
   229  func allocTableSchema() *memdb.TableSchema {
   230  	return &memdb.TableSchema{
   231  		Name: "allocs",
   232  		Indexes: map[string]*memdb.IndexSchema{
   233  			// Primary index is a UUID
   234  			"id": &memdb.IndexSchema{
   235  				Name:         "id",
   236  				AllowMissing: false,
   237  				Unique:       true,
   238  				Indexer: &memdb.UUIDFieldIndex{
   239  					Field: "ID",
   240  				},
   241  			},
   242  
   243  			// Node index is used to lookup allocations by node
   244  			"node": &memdb.IndexSchema{
   245  				Name:         "node",
   246  				AllowMissing: true, // Missing is allow for failed allocations
   247  				Unique:       false,
   248  				Indexer: &memdb.CompoundIndex{
   249  					Indexes: []memdb.Indexer{
   250  						&memdb.StringFieldIndex{
   251  							Field:     "NodeID",
   252  							Lowercase: true,
   253  						},
   254  
   255  						// Conditional indexer on if allocation is terminal
   256  						&memdb.ConditionalIndex{
   257  							Conditional: func(obj interface{}) (bool, error) {
   258  								// Cast to allocation
   259  								alloc, ok := obj.(*structs.Allocation)
   260  								if !ok {
   261  									return false, fmt.Errorf("wrong type, got %t should be Allocation", obj)
   262  								}
   263  
   264  								// Check if the allocation is terminal
   265  								return alloc.TerminalStatus(), nil
   266  							},
   267  						},
   268  					},
   269  				},
   270  			},
   271  
   272  			// Job index is used to lookup allocations by job
   273  			"job": &memdb.IndexSchema{
   274  				Name:         "job",
   275  				AllowMissing: false,
   276  				Unique:       false,
   277  				Indexer: &memdb.StringFieldIndex{
   278  					Field:     "JobID",
   279  					Lowercase: true,
   280  				},
   281  			},
   282  
   283  			// Eval index is used to lookup allocations by eval
   284  			"eval": &memdb.IndexSchema{
   285  				Name:         "eval",
   286  				AllowMissing: false,
   287  				Unique:       false,
   288  				Indexer: &memdb.UUIDFieldIndex{
   289  					Field: "EvalID",
   290  				},
   291  			},
   292  		},
   293  	}
   294  }
   295  
   296  // vaultAccessorTableSchema returns the MemDB schema for the Vault Accessor
   297  // Table. This table tracks Vault accessors for tokens created on behalf of
   298  // allocations required Vault tokens.
   299  func vaultAccessorTableSchema() *memdb.TableSchema {
   300  	return &memdb.TableSchema{
   301  		Name: "vault_accessors",
   302  		Indexes: map[string]*memdb.IndexSchema{
   303  			// The primary index is the accessor id
   304  			"id": &memdb.IndexSchema{
   305  				Name:         "id",
   306  				AllowMissing: false,
   307  				Unique:       true,
   308  				Indexer: &memdb.StringFieldIndex{
   309  					Field: "Accessor",
   310  				},
   311  			},
   312  
   313  			"alloc_id": &memdb.IndexSchema{
   314  				Name:         "alloc_id",
   315  				AllowMissing: false,
   316  				Unique:       false,
   317  				Indexer: &memdb.StringFieldIndex{
   318  					Field: "AllocID",
   319  				},
   320  			},
   321  
   322  			"node_id": &memdb.IndexSchema{
   323  				Name:         "node_id",
   324  				AllowMissing: false,
   325  				Unique:       false,
   326  				Indexer: &memdb.StringFieldIndex{
   327  					Field: "NodeID",
   328  				},
   329  			},
   330  		},
   331  	}
   332  }