github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/nomad/state/schema.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/go-memdb"
     7  	"github.com/ncodes/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, it is not periodic and is not a
   153  	// parameterized job.
   154  	periodic := j.Periodic != nil && j.Periodic.Enabled
   155  	gcable := j.Type == structs.JobTypeBatch && !periodic && !j.IsParameterized()
   156  	return gcable, nil
   157  }
   158  
   159  // jobIsPeriodic satisfies the ConditionalIndexFunc interface and creates an index
   160  // on whether a job is periodic.
   161  func jobIsPeriodic(obj interface{}) (bool, error) {
   162  	j, ok := obj.(*structs.Job)
   163  	if !ok {
   164  		return false, fmt.Errorf("Unexpected type: %v", obj)
   165  	}
   166  
   167  	if j.Periodic != nil && j.Periodic.Enabled == true {
   168  		return true, nil
   169  	}
   170  
   171  	return false, nil
   172  }
   173  
   174  // periodicLaunchTableSchema returns the MemDB schema tracking the most recent
   175  // launch time for a perioidic job.
   176  func periodicLaunchTableSchema() *memdb.TableSchema {
   177  	return &memdb.TableSchema{
   178  		Name: "periodic_launch",
   179  		Indexes: map[string]*memdb.IndexSchema{
   180  			// Primary index is used for job management
   181  			// and simple direct lookup. ID is required to be
   182  			// unique.
   183  			"id": &memdb.IndexSchema{
   184  				Name:         "id",
   185  				AllowMissing: false,
   186  				Unique:       true,
   187  				Indexer: &memdb.StringFieldIndex{
   188  					Field:     "ID",
   189  					Lowercase: true,
   190  				},
   191  			},
   192  		},
   193  	}
   194  }
   195  
   196  // evalTableSchema returns the MemDB schema for the eval table.
   197  // This table is used to store all the evaluations that are pending
   198  // or recently completed.
   199  func evalTableSchema() *memdb.TableSchema {
   200  	return &memdb.TableSchema{
   201  		Name: "evals",
   202  		Indexes: map[string]*memdb.IndexSchema{
   203  			// Primary index is used for direct lookup.
   204  			"id": &memdb.IndexSchema{
   205  				Name:         "id",
   206  				AllowMissing: false,
   207  				Unique:       true,
   208  				Indexer: &memdb.UUIDFieldIndex{
   209  					Field: "ID",
   210  				},
   211  			},
   212  
   213  			// Job index is used to lookup allocations by job
   214  			"job": &memdb.IndexSchema{
   215  				Name:         "job",
   216  				AllowMissing: false,
   217  				Unique:       false,
   218  				Indexer: &memdb.CompoundIndex{
   219  					Indexes: []memdb.Indexer{
   220  						&memdb.StringFieldIndex{
   221  							Field:     "JobID",
   222  							Lowercase: true,
   223  						},
   224  						&memdb.StringFieldIndex{
   225  							Field:     "Status",
   226  							Lowercase: true,
   227  						},
   228  					},
   229  				},
   230  			},
   231  		},
   232  	}
   233  }
   234  
   235  // allocTableSchema returns the MemDB schema for the allocation table.
   236  // This table is used to store all the task allocations between task groups
   237  // and nodes.
   238  func allocTableSchema() *memdb.TableSchema {
   239  	return &memdb.TableSchema{
   240  		Name: "allocs",
   241  		Indexes: map[string]*memdb.IndexSchema{
   242  			// Primary index is a UUID
   243  			"id": &memdb.IndexSchema{
   244  				Name:         "id",
   245  				AllowMissing: false,
   246  				Unique:       true,
   247  				Indexer: &memdb.UUIDFieldIndex{
   248  					Field: "ID",
   249  				},
   250  			},
   251  
   252  			// Node index is used to lookup allocations by node
   253  			"node": &memdb.IndexSchema{
   254  				Name:         "node",
   255  				AllowMissing: true, // Missing is allow for failed allocations
   256  				Unique:       false,
   257  				Indexer: &memdb.CompoundIndex{
   258  					Indexes: []memdb.Indexer{
   259  						&memdb.StringFieldIndex{
   260  							Field:     "NodeID",
   261  							Lowercase: true,
   262  						},
   263  
   264  						// Conditional indexer on if allocation is terminal
   265  						&memdb.ConditionalIndex{
   266  							Conditional: func(obj interface{}) (bool, error) {
   267  								// Cast to allocation
   268  								alloc, ok := obj.(*structs.Allocation)
   269  								if !ok {
   270  									return false, fmt.Errorf("wrong type, got %t should be Allocation", obj)
   271  								}
   272  
   273  								// Check if the allocation is terminal
   274  								return alloc.TerminalStatus(), nil
   275  							},
   276  						},
   277  					},
   278  				},
   279  			},
   280  
   281  			// Job index is used to lookup allocations by job
   282  			"job": &memdb.IndexSchema{
   283  				Name:         "job",
   284  				AllowMissing: false,
   285  				Unique:       false,
   286  				Indexer: &memdb.StringFieldIndex{
   287  					Field:     "JobID",
   288  					Lowercase: true,
   289  				},
   290  			},
   291  
   292  			// Eval index is used to lookup allocations by eval
   293  			"eval": &memdb.IndexSchema{
   294  				Name:         "eval",
   295  				AllowMissing: false,
   296  				Unique:       false,
   297  				Indexer: &memdb.UUIDFieldIndex{
   298  					Field: "EvalID",
   299  				},
   300  			},
   301  		},
   302  	}
   303  }
   304  
   305  // vaultAccessorTableSchema returns the MemDB schema for the Vault Accessor
   306  // Table. This table tracks Vault accessors for tokens created on behalf of
   307  // allocations required Vault tokens.
   308  func vaultAccessorTableSchema() *memdb.TableSchema {
   309  	return &memdb.TableSchema{
   310  		Name: "vault_accessors",
   311  		Indexes: map[string]*memdb.IndexSchema{
   312  			// The primary index is the accessor id
   313  			"id": &memdb.IndexSchema{
   314  				Name:         "id",
   315  				AllowMissing: false,
   316  				Unique:       true,
   317  				Indexer: &memdb.StringFieldIndex{
   318  					Field: "Accessor",
   319  				},
   320  			},
   321  
   322  			"alloc_id": &memdb.IndexSchema{
   323  				Name:         "alloc_id",
   324  				AllowMissing: false,
   325  				Unique:       false,
   326  				Indexer: &memdb.StringFieldIndex{
   327  					Field: "AllocID",
   328  				},
   329  			},
   330  
   331  			"node_id": &memdb.IndexSchema{
   332  				Name:         "node_id",
   333  				AllowMissing: false,
   334  				Unique:       false,
   335  				Indexer: &memdb.StringFieldIndex{
   336  					Field: "NodeID",
   337  				},
   338  			},
   339  		},
   340  	}
   341  }