github.com/kjdelisle/consul@v1.4.5/ui/javascripts/app/routes.js (about) 1 // 2 // Superclass to be used by all of the main routes below. 3 // 4 App.BaseRoute = Ember.Route.extend({ 5 rootKey: '', 6 condensedView: false, 7 8 // Don't record characters in browser history 9 // for the "search" query item (filter) 10 queryParams: { 11 filter: { 12 replace: true 13 } 14 }, 15 16 getParentAndGrandparent: function(key) { 17 var parentKey = this.rootKey, 18 grandParentKey = this.rootKey, 19 parts = key.split('/'); 20 21 if (parts.length > 0) { 22 parts.pop(); 23 parentKey = parts.join("/") + "/"; 24 } 25 26 if (parts.length > 1) { 27 parts.pop(); 28 grandParentKey = parts.join("/") + "/"; 29 } 30 31 return { 32 parent: parentKey, 33 grandParent: grandParentKey, 34 isRoot: parentKey === '/' 35 }; 36 }, 37 38 removeDuplicateKeys: function(keys, matcher) { 39 // Loop over the keys 40 keys.forEach(function(item, index) { 41 if (item.get('Key') == matcher) { 42 // If we are in a nested folder and the folder 43 // name matches our position, remove it 44 keys.splice(index, 1); 45 } 46 }); 47 return keys; 48 }, 49 50 actions: { 51 // Used to link to keys that are not objects, 52 // like parents and grandParents 53 linkToKey: function(key) { 54 if (key == "/") { 55 this.transitionTo('kv.show', ""); 56 } 57 else if (key.slice(-1) === '/' || key === this.rootKey) { 58 this.transitionTo('kv.show', key); 59 } else { 60 this.transitionTo('kv.edit', key); 61 } 62 } 63 } 64 }); 65 66 // 67 // The route for choosing datacenters, typically the first route loaded. 68 // 69 App.IndexRoute = App.BaseRoute.extend({ 70 // Retrieve the list of datacenters 71 model: function(params) { 72 return Ember.$.getJSON(consulHost + '/v1/catalog/datacenters').then(function(data) { 73 return data; 74 }); 75 }, 76 77 afterModel: function(model, transition) { 78 // If we only have one datacenter, jump 79 // straight to it and bypass the global 80 // view 81 if (model.get('length') === 1) { 82 this.transitionTo('services', model[0]); 83 } 84 } 85 }); 86 87 // The parent route for all resources. This keeps the top bar 88 // functioning, as well as the per-dc requests. 89 App.DcRoute = App.BaseRoute.extend({ 90 model: function(params) { 91 var token = App.get('settings.token'); 92 93 // Return a promise hash to retrieve the 94 // dcs and nodes used in the header 95 return Ember.RSVP.hash({ 96 dc: params.dc, 97 dcs: Ember.$.getJSON(consulHost + '/v1/catalog/datacenters'), 98 nodes: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/nodes', params.dc, token)).then(function(data) { 99 var objs = []; 100 101 // Merge the nodes into a list and create objects out of them 102 data.map(function(obj){ 103 objs.push(App.Node.create(obj)); 104 }); 105 106 return objs; 107 }), 108 coordinates: Ember.$.getJSON(formatUrl(consulHost + '/v1/coordinate/nodes', params.dc, token)).then(function(data) { 109 return data; 110 }) 111 }); 112 }, 113 114 setupController: function(controller, models) { 115 controller.set('content', models.dc); 116 controller.set('nodes', models.nodes); 117 controller.set('dcs', models.dcs); 118 controller.set('coordinates', models.coordinates); 119 controller.set('isDropdownVisible', false); 120 }, 121 }); 122 123 App.KvIndexRoute = App.BaseRoute.extend({ 124 beforeModel: function() { 125 this.transitionTo('kv.show', this.rootKey); 126 } 127 }); 128 129 App.KvShowRoute = App.BaseRoute.extend({ 130 model: function(params) { 131 var key = params.key; 132 var dc = this.modelFor('dc').dc; 133 var token = App.get('settings.token'); 134 135 // Return a promise has with the ?keys for that namespace 136 // and the original key requested in params 137 return Ember.RSVP.hash({ 138 key: key, 139 keys: Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + key + '?keys&seperator=/', dc, token)).then(function(data) { 140 var objs = []; 141 data.map(function(obj){ 142 objs.push(App.Key.create({Key: obj})); 143 }); 144 return objs; 145 }) 146 }); 147 }, 148 149 setupController: function(controller, models) { 150 var key = models.key; 151 var parentKeys = this.getParentAndGrandparent(key); 152 models.keys = this.removeDuplicateKeys(models.keys, models.key); 153 154 controller.set('content', models.keys); 155 controller.set('parentKey', parentKeys.parent); 156 controller.set('grandParentKey', parentKeys.grandParent); 157 controller.set('isRoot', parentKeys.isRoot); 158 controller.set('newKey', App.Key.create()); 159 controller.set('rootKey', this.rootKey); 160 } 161 }); 162 163 App.KvEditRoute = App.BaseRoute.extend({ 164 model: function(params) { 165 var key = params.key; 166 var dc = this.modelFor('dc').dc; 167 var parentKeys = this.getParentAndGrandparent(key); 168 var token = App.get('settings.token'); 169 170 // Return a promise hash to get the data for both columns 171 return Ember.RSVP.hash({ 172 dc: dc, 173 token: token, 174 key: Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + key, dc, token)).then(function(data) { 175 // Convert the returned data to a Key 176 return App.Key.create().setProperties(data[0]); 177 }), 178 keys: keysPromise = Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + parentKeys.parent + '?keys&seperator=/', dc, token)).then(function(data) { 179 var objs = []; 180 data.map(function(obj){ 181 objs.push(App.Key.create({Key: obj})); 182 }); 183 return objs; 184 }), 185 }); 186 }, 187 188 // Load the session on the key, if there is one 189 afterModel: function(models) { 190 if (models.key.get('isLocked')) { 191 return Ember.$.getJSON(formatUrl(consulHost + '/v1/session/info/' + models.key.Session, models.dc, models.token)).then(function(data) { 192 models.session = data[0]; 193 return models; 194 }); 195 } else { 196 return models; 197 } 198 }, 199 200 setupController: function(controller, models) { 201 var key = models.key; 202 var parentKeys = this.getParentAndGrandparent(key.get('Key')); 203 models.keys = this.removeDuplicateKeys(models.keys, parentKeys.parent); 204 205 controller.set('content', models.key); 206 controller.set('parentKey', parentKeys.parent); 207 controller.set('grandParentKey', parentKeys.grandParent); 208 controller.set('isRoot', parentKeys.isRoot); 209 controller.set('siblings', models.keys); 210 controller.set('rootKey', this.rootKey); 211 controller.set('session', models.session); 212 } 213 }); 214 215 App.ServicesRoute = App.BaseRoute.extend({ 216 model: function(params) { 217 var dc = this.modelFor('dc').dc; 218 var token = App.get('settings.token'); 219 220 // Return a promise to retrieve all of the services 221 return Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/services', dc, token)).then(function(data) { 222 var objs = []; 223 data.map(function(obj){ 224 objs.push(App.Service.create(obj)); 225 }); 226 return objs; 227 }); 228 }, 229 setupController: function(controller, model) { 230 controller.set('services', model); 231 } 232 }); 233 234 235 App.ServicesShowRoute = App.BaseRoute.extend({ 236 model: function(params) { 237 var dc = this.modelFor('dc').dc; 238 var token = App.get('settings.token'); 239 240 // Here we just use the built-in health endpoint, as it gives us everything 241 // we need. 242 return Ember.$.getJSON(formatUrl(consulHost + '/v1/health/service/' + params.name, dc, token)).then(function(data) { 243 var objs = []; 244 data.map(function(obj){ 245 objs.push(App.Node.create(obj)); 246 }); 247 return objs; 248 }); 249 }, 250 setupController: function(controller, model) { 251 var tags = []; 252 model.map(function(obj){ 253 if (obj.Service.Tags !== null) { 254 tags = tags.concat(obj.Service.Tags); 255 } 256 }); 257 258 tags = tags.filter(function(n){ return n !== undefined; }); 259 tags = tags.uniq().join(', '); 260 261 controller.set('content', model); 262 controller.set('tags', tags); 263 } 264 }); 265 266 function distance(a, b) { 267 a = a.Coord; 268 b = b.Coord; 269 var sum = 0; 270 for (var i = 0; i < a.Vec.length; i++) { 271 var diff = a.Vec[i] - b.Vec[i]; 272 sum += diff * diff; 273 } 274 var rtt = Math.sqrt(sum) + a.Height + b.Height; 275 276 var adjusted = rtt + a.Adjustment + b.Adjustment; 277 if (adjusted > 0.0) { 278 rtt = adjusted; 279 } 280 281 return Math.round(rtt * 100000.0) / 100.0; 282 } 283 284 App.NodesShowRoute = App.BaseRoute.extend({ 285 model: function(params) { 286 var dc = this.modelFor('dc'); 287 var token = App.get('settings.token'); 288 289 var min = 999999999; 290 var max = -999999999; 291 var sum = 0; 292 var distances = []; 293 dc.coordinates.forEach(function (node) { 294 if (params.name == node.Node) { 295 var segment = node.Segment; 296 dc.coordinates.forEach(function (other) { 297 if (node.Node != other.Node && other.Segment == segment) { 298 var dist = distance(node, other); 299 distances.push({ node: other.Node, distance: dist, segment: segment }); 300 sum += dist; 301 if (dist < min) { 302 min = dist; 303 } 304 if (dist > max) { 305 max = dist; 306 } 307 } 308 }); 309 distances.sort(function (a, b) { 310 return a.distance - b.distance; 311 }); 312 } 313 }); 314 var n = distances.length; 315 var halfN = Math.floor(n / 2); 316 var median; 317 318 if (n > 0) { 319 if (n % 2) { 320 // odd 321 median = distances[halfN].distance; 322 } else { 323 median = (distances[halfN - 1].distance + distances[halfN].distance) / 2; 324 } 325 } else { 326 median = 0; 327 min = 0; 328 max = 0; 329 } 330 331 // Return a promise hash of the node 332 return Ember.RSVP.hash({ 333 dc: dc.dc, 334 token: token, 335 tomography: { 336 distances: distances, 337 n: distances.length, 338 min: parseInt(min * 100) / 100, 339 median: parseInt(median * 100) / 100, 340 max: parseInt(max * 100) / 100 341 }, 342 node: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/node/' + params.name, dc.dc, token)).then(function(data) { 343 return App.Node.create(data); 344 }) 345 }); 346 }, 347 348 // Load the sessions for the node 349 afterModel: function(models) { 350 return Ember.$.getJSON(formatUrl(consulHost + '/v1/session/node/' + models.node.Node, models.dc, models.token)).then(function(data) { 351 models.sessions = data; 352 return models; 353 }); 354 }, 355 356 setupController: function(controller, models) { 357 controller.set('content', models.node); 358 controller.set('sessions', models.sessions); 359 controller.set('tomography', models.tomography); 360 } 361 }); 362 363 App.NodesRoute = App.BaseRoute.extend({ 364 model: function(params) { 365 var dc = this.modelFor('dc').dc; 366 var token = App.get('settings.token'); 367 368 // Return a promise containing the nodes 369 return Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/nodes', dc, token)).then(function(data) { 370 var objs = []; 371 data.map(function(obj){ 372 objs.push(App.Node.create(obj)); 373 }); 374 return objs; 375 }); 376 }, 377 setupController: function(controller, model) { 378 controller.set('nodes', model); 379 } 380 }); 381 382 383 App.AclsRoute = App.BaseRoute.extend({ 384 model: function(params) { 385 var dc = this.modelFor('dc').dc; 386 var token = App.get('settings.token'); 387 // Return a promise containing the ACLS 388 return Ember.$.getJSON(formatUrl(consulHost + '/v1/acl/list', dc, token)).then(function(data) { 389 var objs = []; 390 data.map(function(obj){ 391 if (obj.ID === "anonymous") { 392 objs.unshift(App.Acl.create(obj)); 393 } else { 394 objs.push(App.Acl.create(obj)); 395 } 396 }); 397 return objs; 398 }); 399 }, 400 401 actions: { 402 error: function(error, transition) { 403 // If consul returns 401, ACLs are disabled 404 if (error && error.status === 401) { 405 this.transitionTo('dc.aclsdisabled'); 406 // If consul returns 403, they key isn't authorized for that 407 // action. 408 } else if (error && error.status === 403) { 409 this.transitionTo('dc.unauthorized'); 410 } 411 return true; 412 } 413 }, 414 415 setupController: function(controller, model) { 416 controller.set('acls', model); 417 controller.set('newAcl', App.Acl.create()); 418 } 419 }); 420 421 App.AclsShowRoute = App.BaseRoute.extend({ 422 model: function(params) { 423 var dc = this.modelFor('dc').dc; 424 var token = App.get('settings.token'); 425 426 // Return a promise hash of the ACLs 427 return Ember.RSVP.hash({ 428 dc: dc, 429 acl: Ember.$.getJSON(formatUrl(consulHost + '/v1/acl/info/'+ params.id, dc, token)).then(function(data) { 430 return App.Acl.create(data[0]); 431 }) 432 }); 433 }, 434 435 setupController: function(controller, models) { 436 controller.set('content', models.acl); 437 } 438 }); 439 440 App.SettingsRoute = App.BaseRoute.extend({ 441 model: function(params) { 442 return App.get('settings'); 443 } 444 }); 445 446 447 // Adds any global parameters we need to set to a url/path 448 function formatUrl(url, dc, token) { 449 if (token == null) { 450 token = ""; 451 } 452 if (url.indexOf("?") > 0) { 453 // If our url has existing params 454 url = url + "&dc=" + dc; 455 url = url + "&token=" + token; 456 } else { 457 // Our url doesn't have params 458 url = url + "?dc=" + dc; 459 url = url + "&token=" + token; 460 } 461 return url; 462 }