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 }