| OLD | NEW |
| 1 <!-- | 1 <!-- |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. | 2 Copyright 2016 The LUCI Authors. All rights reserved. |
| 3 Use of this source code is governed under the Apache License, Version 2.0 | 3 Use of this source code is governed under the Apache License, Version 2.0 |
| 4 that can be found in the LICENSE file. | 4 that can be found in the LICENSE file. |
| 5 | 5 |
| 6 This in an HTML Import-able file that contains the definition | 6 This in an HTML Import-able file that contains the definition |
| 7 of the following elements: | 7 of the following elements: |
| 8 | 8 |
| 9 <bot-list-data> | 9 <bot-list-data> |
| 10 | 10 |
| 11 This makes calls authenticated with Oauth 2 to the swarming apis. It parses | 11 This makes calls authenticated with Oauth 2 to the swarming apis. It parses |
| 12 that data into usable data structures. | 12 that data into usable data structures. |
| 13 | 13 |
| 14 Usage: | 14 Usage: |
| 15 | 15 |
| 16 <bot-list-data></bot-list-data> | 16 <bot-list-data></bot-list-data> |
| 17 | 17 |
| 18 Properties: | 18 Properties: |
| 19 // inputs | 19 // inputs |
| 20 auth_headers: Object, the OAuth2 header to include in the request. This | 20 auth_headers: Object, the OAuth2 header to include in the request. This |
| 21 should come from swarming-app. | 21 should come from swarming-app. |
| 22 query_params: Object, The query params that will filter the query |
| 23 server-side. This can have dimensions:Array<String>, quarantined:String |
| 24 and is_dead: String. For example: |
| 25 { |
| 26 "dimensions": ["pool:Skia", "device_type:Sprout"], |
| 27 "quarantined": "FALSE", // optional |
| 28 "is_dead": "TRUE", // optional |
| 29 } |
| 30 For a full list of dimensions in the fleet, see the API call: |
| 31 https://[swarming_url]/_ah/api/swarming/v1/bots/dimensions |
| 22 // outputs | 32 // outputs |
| 23 bots: Array<Object>, all bots returned by the botlist. This is an Object | 33 bots: Array<Object>, all bots returned by the botlist. This is an Object |
| 24 with at least the following structure: | 34 with at least the following structure: |
| 25 dimensions: Array<Object>: Has key:String and value:Array<String> | 35 dimensions: Array<Object>: Has key:String and value:Array<String> |
| 26 task_id: String | 36 task_id: String |
| 27 external_ip: String | 37 external_ip: String |
| 28 is_dead: Object: Is usually Boolean, but could be message string | 38 is_dead: Object: Is usually Boolean, but could be message string |
| 29 quarantined: Object: Is usually Boolean, but could be message string | 39 quarantined: Object: Is usually Boolean, but could be message string |
| 30 bot_id: String | 40 bot_id: String |
| 31 state: String, Stringified JSON that has many pieces of information, like | 41 state: String, Stringified JSON that has many pieces of information, like |
| 32 devices, disk space, temperature, etc. | 42 devices, disk space, temperature, etc. |
| 33 busy: Boolean, if any ajax requests are in flight. | 43 busy: Boolean, if any ajax requests are in flight. |
| 44 dimensions: Array<String>, of all valid dimensions. |
| 34 fleet: Object, counts of all bots in the fleet. Contains "alive", "busy", | 45 fleet: Object, counts of all bots in the fleet. Contains "alive", "busy", |
| 35 "idle", "dead", and "quarantined". | 46 "idle", "dead", and "quarantined". |
| 36 primary_map: Object, a mapping of primary keys to secondary items. | 47 primary_map: Object, a mapping of primary keys to secondary items. |
| 37 The primary keys are things that can be columns or sorted by. The | 48 The primary keys are things that can be columns or sorted by. The |
| 38 primary values (aka the secondary items) are things that can be filtered | 49 primary values (aka the secondary items) are things that can be filtered |
| 39 on. Primary consists of dimensions and state. Secondary contains the | 50 on. Primary consists of dimensions and state. Secondary contains the |
| 40 values primary things can be. | 51 values primary things can be. |
| 41 primary_arr: Array<String>, the display order of the primary keys. | 52 primary_arr: Array<String>, the display order of the primary keys. |
| 42 This is dimensions, then bot properties, then elements from bot.state. | 53 This is dimensions, then bot properties, then elements from bot.state. |
| 43 | 54 |
| 44 Methods: | 55 Methods: |
| 45 signIn(): Force a signin of the user using OAuth. This happens | 56 signIn(): Force a signin of the user using OAuth. This happens |
| 46 automatically when auth_headers is set. | 57 automatically when auth_headers is set. |
| 47 | 58 |
| 48 Events: | 59 Events: |
| 49 None. | 60 None. |
| 50 --> | 61 --> |
| 51 | 62 |
| 52 <link rel="import" href="/res/imp/bower_components/iron-ajax/iron-ajax.html"> | 63 <link rel="import" href="/res/imp/bower_components/iron-ajax/iron-ajax.html"> |
| 53 | 64 |
| 54 <link rel="import" href="bot-list-shared.html"> | 65 <link rel="import" href="bot-list-shared.html"> |
| 55 | 66 |
| 56 <dom-module id="bot-list-data"> | 67 <dom-module id="bot-list-data"> |
| 57 <template> | 68 <template> |
| 58 <iron-ajax id="botlist" | 69 <iron-ajax id="botlist" |
| 59 url="/_ah/api/swarming/v1/bots/list" | 70 url="/_ah/api/swarming/v1/bots/list" |
| 60 headers="[[auth_headers]]" | 71 headers="[[auth_headers]]" |
| 61 params="[[_botlistParams(dimensions.*)]]" | 72 params="[[query_params]]" |
| 62 handle-as="json" | 73 handle-as="json" |
| 63 last-response="{{_list}}" | 74 last-response="{{_list}}" |
| 64 loading="{{_busy1}}"> | 75 loading="{{_busy1}}"> |
| 65 </iron-ajax> | 76 </iron-ajax> |
| 66 | 77 |
| 67 <iron-ajax id="dimensions" | 78 <iron-ajax id="dimensions" |
| 68 url="/_ah/api/swarming/v1/bots/dimensions" | 79 url="/_ah/api/swarming/v1/bots/dimensions" |
| 69 headers="[[auth_headers]]" | 80 headers="[[auth_headers]]" |
| 70 handle-as="json" | 81 handle-as="json" |
| 71 last-response="{{_dimensions}}" | 82 last-response="{{_dimensions}}" |
| 72 loading="{{_busy2}}"> | 83 loading="{{_busy2}}"> |
| 73 </iron-ajax> | 84 </iron-ajax> |
| 74 | 85 |
| 75 <iron-ajax id="fleet" | 86 <iron-ajax id="fleet" |
| 76 url="/_ah/api/swarming/v1/bots/count" | 87 url="/_ah/api/swarming/v1/bots/count" |
| 77 headers="[[auth_headers]]" | 88 headers="[[auth_headers]]" |
| 78 handle-as="json" | 89 handle-as="json" |
| 79 last-response="{{_count}}" | 90 last-response="{{_count}}" |
| 80 loading="{{_busy3}}"> | 91 loading="{{_busy3}}"> |
| 81 </iron-ajax> | 92 </iron-ajax> |
| 82 </template> | 93 </template> |
| 83 <script> | 94 <script> |
| 84 (function(){ | 95 (function(){ |
| 96 var BLACKLIST_DIMENSIONS = ["quarantined", "error"]; |
| 85 | 97 |
| 86 Polymer({ | 98 Polymer({ |
| 87 is: 'bot-list-data', | 99 is: 'bot-list-data', |
| 88 | 100 |
| 89 behaviors: [SwarmingBehaviors.BotListBehavior], | 101 behaviors: [SwarmingBehaviors.BotListBehavior], |
| 90 | 102 |
| 91 properties: { | 103 properties: { |
| 92 // inputs | 104 // inputs |
| 93 auth_headers: { | 105 auth_headers: { |
| 94 type: Object, | 106 type: Object, |
| 95 observer: "signIn", | 107 observer: "signIn", |
| 96 }, | 108 }, |
| 97 dimensions: { | 109 query_params: { |
| 98 type: Array, | 110 type: Object, |
| 99 }, | 111 }, |
| 100 | 112 |
| 101 //outputs | 113 //outputs |
| 102 bots: { | 114 bots: { |
| 103 type: Array, | 115 type: Array, |
| 104 computed: "_bots(_list)", | 116 computed: "_bots(_list)", |
| 105 notify: true, | 117 notify: true, |
| 106 }, | 118 }, |
| 107 busy: { | 119 busy: { |
| 108 type: Boolean, | 120 type: Boolean, |
| 109 computed: "_or(_busy1,_busy2,_busy3)", | 121 computed: "_or(_busy1,_busy2,_busy3)", |
| 110 notify: true, | 122 notify: true, |
| 111 }, | 123 }, |
| 124 dimensions: { |
| 125 type: Array, |
| 126 computed: "_makeArray(_dimensions)", |
| 127 notify: true, |
| 128 }, |
| 112 fleet: { | 129 fleet: { |
| 113 type: Object, | 130 type: Object, |
| 114 computed: "_fleet(_count)", | 131 computed: "_fleet(_count)", |
| 115 notify: true, | 132 notify: true, |
| 116 }, | 133 }, |
| 117 primary_map: { | 134 primary_map: { |
| 118 type:Object, | 135 type:Object, |
| 119 computed: "_primaryMap(_dimensions)", | 136 computed: "_primaryMap(_dimensions)", |
| 120 notify: true, | 137 notify: true, |
| 121 }, | 138 }, |
| 122 primary_arr: { | 139 primary_arr: { |
| 123 type: Array, | 140 type: Array, |
| 124 // DIMENSIONS and BOT_PROPERTIES are inherited from BotListBehavior | 141 //BOT_PROPERTIES is inherited from BotListBehavior |
| 125 computed: "_primaryArr(DIMENSIONS, BOT_PROPERTIES)", | 142 computed: "_primaryArr(dimensions, BOT_PROPERTIES)", |
| 126 notify: true, | 143 notify: true, |
| 127 }, | 144 }, |
| 128 | 145 |
| 129 // private | 146 // private |
| 130 _count: { | 147 _count: { |
| 131 type: Object, | 148 type: Object, |
| 132 }, | 149 }, |
| 133 _dimensions: { | 150 _dimensions: { |
| 134 type: Object, | 151 type: Object, |
| 135 }, | 152 }, |
| 136 _list: { | 153 _list: { |
| 137 type: Object, | 154 type: Object, |
| 138 }, | 155 }, |
| 139 }, | 156 }, |
| 140 | 157 |
| 141 signIn: function(){ | 158 signIn: function(){ |
| 159 // Auto on iron-ajax means to automatically re-make the request if |
| 160 // the url or the query params change. Auto does not trigger if the |
| 161 // [auth] headers change, so we wait until the user is signed in |
| 162 // before making any requests. |
| 142 this.$.botlist.auto = true; | 163 this.$.botlist.auto = true; |
| 143 this.$.dimensions.auto = true; | 164 this.$.dimensions.auto = true; |
| 144 this.$.fleet.auto = true; | 165 this.$.fleet.auto = true; |
| 145 }, | 166 }, |
| 146 | 167 |
| 147 _botlistParams: function() { | |
| 148 if (!this.dimensions) { | |
| 149 return {}; | |
| 150 } | |
| 151 return { | |
| 152 dimensions: this.dimensions, | |
| 153 }; | |
| 154 }, | |
| 155 | |
| 156 _bots: function(){ | 168 _bots: function(){ |
| 157 if (!this._list || !this._list.items) { | 169 if (!this._list || !this._list.items) { |
| 158 return []; | 170 return []; |
| 159 } | 171 } |
| 160 // Do any preprocessing here | 172 // Do any preprocessing here |
| 161 this._list.items.forEach(function(bot){ | 173 this._list.items.forEach(function(bot){ |
| 162 // Parse the state, which is a JSON string. This contains a lot of | 174 // Parse the state, which is a JSON string. This contains a lot of |
| 163 // interesting information like details about the devices attached. | 175 // interesting information like details about the devices attached. |
| 164 bot.state = JSON.parse(bot.state); | 176 bot.state = JSON.parse(bot.state); |
| 165 // get the disks in an easier to deal with format, sorted by size. | 177 // get the disks in an easier to deal with format, sorted by size. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 180 | 192 |
| 181 }); | 193 }); |
| 182 return this._list.items; | 194 return this._list.items; |
| 183 }, | 195 }, |
| 184 | 196 |
| 185 _fleet: function() { | 197 _fleet: function() { |
| 186 if (!this._count) { | 198 if (!this._count) { |
| 187 return {}; | 199 return {}; |
| 188 } | 200 } |
| 189 return { | 201 return { |
| 190 alive: this._count.count || -1, | 202 all: this._count.count || -1, |
| 203 alive: (this._count.count - this._count.dead) || -1, |
| 191 busy: this._count.busy || -1, | 204 busy: this._count.busy || -1, |
| 192 idle: this._count.count && this._count.busy && | 205 idle: (this._count.count - this._count.busy) || -1, |
| 193 this._count.count - this._count.busy, | |
| 194 dead: this._count.dead || -1, | 206 dead: this._count.dead || -1, |
| 195 quarantined: this._count.quarantined || -1, | 207 quarantined: this._count.quarantined || -1, |
| 196 } | 208 } |
| 197 }, | 209 }, |
| 198 | 210 |
| 211 _makeArray: function(dimObj) { |
| 212 if (!dimObj || !dimObj.bots_dimensions) { |
| 213 return []; |
| 214 } |
| 215 var dims = []; |
| 216 dimObj.bots_dimensions.forEach(function(d){ |
| 217 if (BLACKLIST_DIMENSIONS.indexOf(d.key) === -1) { |
| 218 dims.push(d.key); |
| 219 } |
| 220 }); |
| 221 dims.sort(); |
| 222 return dims; |
| 223 }, |
| 224 |
| 199 _primaryArr: function(dimensions, properties) { | 225 _primaryArr: function(dimensions, properties) { |
| 200 return dimensions.concat(properties); | 226 return dimensions.concat(properties); |
| 201 }, | 227 }, |
| 202 | 228 |
| 203 _primaryMap: function(dimensions){ | 229 _primaryMap: function(dimensions){ |
| 204 // map will keep track of dimensions that we have seen at least once. | 230 // pMap will have a list of columns to available values (primary key |
| 205 // This will then basically get turned into an array to be used for | 231 // to secondary values). This includes bot dimensions, but also |
| 206 // filtering. | 232 // includes state like disk_space, quarantined, busy, etc. |
| 207 dimensions = dimensions.bots_dimensions; | 233 dimensions = dimensions.bots_dimensions; |
| 208 | 234 |
| 209 var pMap = {}; | 235 var pMap = {}; |
| 210 dimensions.forEach(function(d){ | 236 dimensions.forEach(function(d){ |
| 211 if (this.DIMENSIONS_WITH_ALIASES.indexOf(d.key) === -1) { | 237 if (this.DIMENSIONS_WITH_ALIASES.indexOf(d.key) === -1) { |
| 212 // value is an array of all seen values for the dimension d.key | 238 // value is an array of all seen values for the dimension d.key |
| 213 pMap[d.key] = d.value; | 239 pMap[d.key] = d.value; |
| 214 } else if (d.key === "gpu") { | 240 } else if (d.key === "gpu") { |
| 215 var gpus = []; | 241 var gpus = []; |
| 216 d.value.forEach(function(g){ | 242 d.value.forEach(function(g){ |
| (...skipping 24 matching lines...) Expand all Loading... |
| 241 // Add some options that might not show up. | 267 // Add some options that might not show up. |
| 242 pMap["android_devices"].push("0"); | 268 pMap["android_devices"].push("0"); |
| 243 pMap["device_os"].push("none"); | 269 pMap["device_os"].push("none"); |
| 244 pMap["device_type"].push("none"); | 270 pMap["device_type"].push("none"); |
| 245 | 271 |
| 246 pMap["id"] = []; | 272 pMap["id"] = []; |
| 247 | 273 |
| 248 // Create custom filter options | 274 // Create custom filter options |
| 249 pMap["disk_space"] = []; | 275 pMap["disk_space"] = []; |
| 250 pMap["task"] = ["busy", "idle"]; | 276 pMap["task"] = ["busy", "idle"]; |
| 251 pMap["status"] = ["available", "dead", "quarantined"]; | 277 pMap["status"] = ["alive", "dead", "quarantined"]; |
| 252 | 278 |
| 253 // No need to sort any of this, bot-filters sorts secondary items | 279 // No need to sort any of this, bot-filters sorts secondary items |
| 254 // automatically, especially when the user types a query. | 280 // automatically, especially when the user types a query. |
| 255 return pMap; | 281 return pMap; |
| 256 }, | 282 }, |
| 257 | 283 |
| 258 }); | 284 }); |
| 259 })(); | 285 })(); |
| 260 </script> | 286 </script> |
| 261 </dom-module> | 287 </dom-module> |
| OLD | NEW |