github.com/emate/nomad@v0.8.2-wo-binpacking/ui/mirage/config.js (about) 1 import Ember from 'ember'; 2 import Response from 'ember-cli-mirage/response'; 3 import { HOSTS } from './common'; 4 import { logFrames, logEncode } from './data/logs'; 5 6 const { copy } = Ember; 7 8 export function findLeader(schema) { 9 const agent = schema.agents.first(); 10 return `${agent.address}:${agent.tags.port}`; 11 } 12 13 export default function() { 14 this.timing = 0; // delay for each request, automatically set to 0 during testing 15 16 this.namespace = 'v1'; 17 this.trackRequests = Ember.testing; 18 19 const nomadIndices = {}; // used for tracking blocking queries 20 const server = this; 21 const withBlockingSupport = function(fn) { 22 return function(schema, request) { 23 // Get the original response 24 let { url } = request; 25 url = url.replace(/index=\d+[&;]?/, ''); 26 const response = fn.apply(this, arguments); 27 28 // Get and increment the appropriate index 29 nomadIndices[url] || (nomadIndices[url] = 2); 30 const index = nomadIndices[url]; 31 nomadIndices[url]++; 32 33 // Annotate the response with the index 34 if (response instanceof Response) { 35 response.headers['X-Nomad-Index'] = index; 36 return response; 37 } 38 return new Response(200, { 'x-nomad-index': index }, response); 39 }; 40 }; 41 42 this.get( 43 '/jobs', 44 withBlockingSupport(function({ jobs }, { queryParams }) { 45 const json = this.serialize(jobs.all()); 46 const namespace = queryParams.namespace || 'default'; 47 return json 48 .filter( 49 job => 50 namespace === 'default' 51 ? !job.NamespaceID || job.NamespaceID === namespace 52 : job.NamespaceID === namespace 53 ) 54 .map(job => filterKeys(job, 'TaskGroups', 'NamespaceID')); 55 }) 56 ); 57 58 this.get( 59 '/job/:id', 60 withBlockingSupport(function({ jobs }, { params, queryParams }) { 61 const job = jobs.all().models.find(job => { 62 const jobIsDefault = !job.namespaceId || job.namespaceId === 'default'; 63 const qpIsDefault = !queryParams.namespace || queryParams.namespace === 'default'; 64 return ( 65 job.id === params.id && 66 (job.namespaceId === queryParams.namespace || (jobIsDefault && qpIsDefault)) 67 ); 68 }); 69 70 return job ? this.serialize(job) : new Response(404, {}, null); 71 }) 72 ); 73 74 this.get( 75 '/job/:id/summary', 76 withBlockingSupport(function({ jobSummaries }, { params }) { 77 return this.serialize(jobSummaries.findBy({ jobId: params.id })); 78 }) 79 ); 80 81 this.get('/job/:id/allocations', function({ allocations }, { params }) { 82 return this.serialize(allocations.where({ jobId: params.id })); 83 }); 84 85 this.get('/job/:id/versions', function({ jobVersions }, { params }) { 86 return this.serialize(jobVersions.where({ jobId: params.id })); 87 }); 88 89 this.get('/job/:id/deployments', function({ deployments }, { params }) { 90 return this.serialize(deployments.where({ jobId: params.id })); 91 }); 92 93 this.post('/job/:id/periodic/force', function(schema, { params }) { 94 // Create the child job 95 const parent = schema.jobs.find(params.id); 96 97 // Use the server instead of the schema to leverage the job factory 98 server.create('job', 'periodicChild', { 99 parentId: parent.id, 100 namespaceId: parent.namespaceId, 101 namespace: parent.namespace, 102 createAllocations: parent.createAllocations, 103 }); 104 105 // Return bogus, since the response is normally just eval information 106 return new Response(200, {}, '{}'); 107 }); 108 109 this.delete('/job/:id', function(schema, { params }) { 110 const job = schema.jobs.find(params.id); 111 job.update({ status: 'dead' }); 112 return new Response(204, {}, ''); 113 }); 114 115 this.get('/deployment/:id'); 116 117 this.get('/job/:id/evaluations', function({ evaluations }, { params }) { 118 return this.serialize(evaluations.where({ jobId: params.id })); 119 }); 120 121 this.get('/evaluation/:id'); 122 123 this.get('/deployment/allocations/:id', function(schema, { params }) { 124 const job = schema.jobs.find(schema.deployments.find(params.id).jobId); 125 const allocations = schema.allocations.where({ jobId: job.id }); 126 127 return this.serialize(allocations.slice(0, 3)); 128 }); 129 130 this.get('/nodes', function({ nodes }) { 131 const json = this.serialize(nodes.all()); 132 return json; 133 }); 134 135 this.get('/node/:id'); 136 137 this.get('/node/:id/allocations', function({ allocations }, { params }) { 138 return this.serialize(allocations.where({ nodeId: params.id })); 139 }); 140 141 this.get('/allocations'); 142 143 this.get('/allocation/:id'); 144 145 this.get('/namespaces', function({ namespaces }) { 146 const records = namespaces.all(); 147 148 if (records.length) { 149 return this.serialize(records); 150 } 151 152 return new Response(501, {}, null); 153 }); 154 155 this.get('/namespace/:id', function({ namespaces }, { params }) { 156 if (namespaces.all().length) { 157 return this.serialize(namespaces.find(params.id)); 158 } 159 160 return new Response(501, {}, null); 161 }); 162 163 this.get('/agent/members', function({ agents }) { 164 return { 165 Members: this.serialize(agents.all()), 166 }; 167 }); 168 169 this.get('/status/leader', function(schema) { 170 return JSON.stringify(findLeader(schema)); 171 }); 172 173 this.get('/acl/token/self', function({ tokens }, req) { 174 const secret = req.requestHeaders['X-Nomad-Token']; 175 const tokenForSecret = tokens.findBy({ secretId: secret }); 176 177 // Return the token if it exists 178 if (tokenForSecret) { 179 return this.serialize(tokenForSecret); 180 } 181 182 // Client error if it doesn't 183 return new Response(400, {}, null); 184 }); 185 186 this.get('/acl/token/:id', function({ tokens }, req) { 187 const token = tokens.find(req.params.id); 188 const secret = req.requestHeaders['X-Nomad-Token']; 189 const tokenForSecret = tokens.findBy({ secretId: secret }); 190 191 // Return the token only if the request header matches the token 192 // or the token is of type management 193 if (token.secretId === secret || (tokenForSecret && tokenForSecret.type === 'management')) { 194 return this.serialize(token); 195 } 196 197 // Return not authorized otherwise 198 return new Response(403, {}, null); 199 }); 200 201 this.get('/acl/policy/:id', function({ policies, tokens }, req) { 202 const policy = policies.find(req.params.id); 203 const secret = req.requestHeaders['X-Nomad-Token']; 204 const tokenForSecret = tokens.findBy({ secretId: secret }); 205 206 // Return the policy only if the token that matches the request header 207 // includes the policy or if the token that matches the request header 208 // is of type management 209 if ( 210 tokenForSecret && 211 (tokenForSecret.policies.includes(policy) || tokenForSecret.type === 'management') 212 ) { 213 return this.serialize(policy); 214 } 215 216 // Return not authorized otherwise 217 return new Response(403, {}, null); 218 }); 219 220 const clientAllocationStatsHandler = function({ clientAllocationStats }, { params }) { 221 return this.serialize(clientAllocationStats.find(params.id)); 222 }; 223 224 const clientAllocationLog = function(server, { params, queryParams }) { 225 const allocation = server.allocations.find(params.allocation_id); 226 const tasks = allocation.taskStateIds.map(id => server.taskStates.find(id)); 227 228 if (!tasks.mapBy('name').includes(queryParams.task)) { 229 return new Response(400, {}, 'must include task name'); 230 } 231 232 if (queryParams.plain) { 233 return logFrames.join(''); 234 } 235 236 return logEncode(logFrames, logFrames.length - 1); 237 }; 238 239 // Client requests are available on the server and the client 240 this.get('/client/allocation/:id/stats', clientAllocationStatsHandler); 241 this.get('/client/fs/logs/:allocation_id', clientAllocationLog); 242 243 this.get('/client/v1/client/stats', function({ clientStats }, { queryParams }) { 244 return this.serialize(clientStats.find(queryParams.node_id)); 245 }); 246 247 // TODO: in the future, this hack may be replaceable with dynamic host name 248 // support in pretender: https://github.com/pretenderjs/pretender/issues/210 249 HOSTS.forEach(host => { 250 this.get(`http://${host}/v1/client/allocation/:id/stats`, clientAllocationStatsHandler); 251 this.get(`http://${host}/v1/client/fs/logs/:allocation_id`, clientAllocationLog); 252 253 this.get(`http://${host}/v1/client/stats`, function({ clientStats }) { 254 return this.serialize(clientStats.find(host)); 255 }); 256 }); 257 } 258 259 function filterKeys(object, ...keys) { 260 const clone = copy(object, true); 261 262 keys.forEach(key => { 263 delete clone[key]; 264 }); 265 266 return clone; 267 }