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 }