| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. | |
| 3 Use of this source code is governed under the Apache License, Version 2.0 | |
| 4 that can be found in the LICENSE file. | |
| 5 | |
| 6 This in an HTML Import-able file that contains the definition | |
| 7 of the following elements: | |
| 8 | |
| 9 <bot-page-data> | |
| 10 | |
| 11 This makes calls authenticated with Oauth 2 to the swarming apis. It parses | |
| 12 that data into usable data structures. | |
| 13 | |
| 14 Properties: | |
| 15 // input | |
| 16 auth_headers: Object, the OAuth2 header to include in the request. This | |
| 17 should come from swarming-app. | |
| 18 bot_id: String, the id of the bot to fetch data on. | |
| 19 // output | |
| 20 bot: Object, The information about the bot. See swarming_rpcs.py#BotInfo | |
| 21 for all relevent fields. | |
| 22 busy: Boolean, if we are fetching any data from the server. | |
| 23 events: Array<Object>, The most recent events that pertain to this bot. | |
| 24 Contains the following fields: "event_type", "message", "ts" (timestamp)
, | |
| 25 "quarantined", "version". | |
| 26 tasks: Array<Object>, The most recent tasks done by this bot. | |
| 27 Contains the following fields: "abandoned_ts", "bot_version", "duration"
, | |
| 28 "failure", "internal_failure", "modified_ts", "name", "started_ts", | |
| 29 "state", "task_id", "try_number". | |
| 30 | |
| 31 Methods: | |
| 32 parseEvents(json): Given the json returned by the server on a request to | |
| 33 api/swarming/v1/bot/[botid]/events, return an array of event Objects. | |
| 34 | |
| 35 parseTasks(json): Given the json returned by the server on a request to | |
| 36 api/swarming/v1/bot/[botid]/events, return an array of task Objects. | |
| 37 | |
| 38 request(): Force a fetch of the data. This happens automatically when | |
| 39 auth_headers is set or bot_id is changed. | |
| 40 | |
| 41 Events: | |
| 42 reload: When this element is making a request for data. Other data sources | |
| 43 should also reload themselves. | |
| 44 --> | |
| 45 | |
| 46 | |
| 47 <link rel="import" href="bot-page-shared-behavior.html"> | |
| 48 | |
| 49 <dom-module id="bot-page-data"> | |
| 50 <script> | |
| 51 (function(){ | |
| 52 // Time to wait before requesting a new bot. This is to allow a user to | |
| 53 // type in a name and not have it make one set of requests for each | |
| 54 // keystroke. | |
| 55 var BOT_ID_DEBOUNCE_MS = 400; | |
| 56 var lastRequest; | |
| 57 | |
| 58 var BOT_TIMES = ["first_seen_ts", "last_seen_ts", "lease_expiration_ts"]; | |
| 59 var TASK_TIMES = ["started_ts", "completed_ts", "abandoned_ts", "modified_ts
"]; | |
| 60 | |
| 61 var timezone; | |
| 62 function formatDate(date) { | |
| 63 if (!timezone) { | |
| 64 // Date.toString() looks like "Mon Aug 29 2016 09:03:41 GMT-0400 (EDT)" | |
| 65 // we want to extract the time zone part and append it to the | |
| 66 // locale time. | |
| 67 var str = date.toString(); | |
| 68 timezone = str.substring(str.indexOf("(")); | |
| 69 } | |
| 70 return date.toLocaleString() + " " + timezone; | |
| 71 } | |
| 72 | |
| 73 Polymer({ | |
| 74 is: 'bot-page-data', | |
| 75 | |
| 76 behaviors: [ | |
| 77 SwarmingBehaviors.BotPageBehavior, | |
| 78 ], | |
| 79 | |
| 80 properties: { | |
| 81 // inputs | |
| 82 auth_headers: { | |
| 83 type: Object, | |
| 84 }, | |
| 85 bot_id: { | |
| 86 type: String, | |
| 87 }, | |
| 88 | |
| 89 // outputs | |
| 90 busy: { | |
| 91 type: Boolean, | |
| 92 computed: "_or(_busy1)", | |
| 93 notify: true, | |
| 94 }, | |
| 95 bot: { | |
| 96 type: Object, | |
| 97 computed: "_parseBot(_bot)", | |
| 98 notify: true, | |
| 99 }, | |
| 100 | |
| 101 // private | |
| 102 _busy1: { | |
| 103 type: Boolean, | |
| 104 value: false | |
| 105 }, | |
| 106 _bot: { | |
| 107 type: Object, | |
| 108 }, | |
| 109 _events: { | |
| 110 type: Object, | |
| 111 }, | |
| 112 _tasks: { | |
| 113 type: Object, | |
| 114 }, | |
| 115 }, | |
| 116 | |
| 117 observers: [ | |
| 118 "request(auth_headers,bot_id)", | |
| 119 ], | |
| 120 | |
| 121 request: function(){ | |
| 122 if (!this.bot_id || !this.auth_headers) { | |
| 123 return; | |
| 124 } | |
| 125 if (lastRequest) { | |
| 126 this.cancelAsync(lastRequest); | |
| 127 } | |
| 128 | |
| 129 lastRequest = this.async(function(){ | |
| 130 lastRequest = undefined; | |
| 131 var baseUrl = "/_ah/api/swarming/v1/bot/"+this.bot_id; | |
| 132 this._getJsonAsync("_bot", baseUrl + "/get", | |
| 133 "_busy1", this.auth_headers); | |
| 134 this.fire("reload", {id: this.bot_id}); | |
| 135 }, BOT_ID_DEBOUNCE_MS); | |
| 136 | |
| 137 }, | |
| 138 | |
| 139 _parseBot: function(bot) { | |
| 140 if (!bot) { | |
| 141 return {}; | |
| 142 } | |
| 143 // Do any preprocessing here | |
| 144 bot.state = bot.state || "{}"; | |
| 145 bot.state = JSON.parse(bot.state) || {}; | |
| 146 | |
| 147 // get the disks in an easier to deal with format, sorted by size. | |
| 148 var disks = bot.state.disks || {}; | |
| 149 var keys = Object.keys(disks); | |
| 150 if (!keys.length) { | |
| 151 bot.disks = [{"id": "unknown", "mb": 0}]; | |
| 152 } else { | |
| 153 bot.disks = []; | |
| 154 for (var i = 0; i < keys.length; i++) { | |
| 155 bot.disks.push({"id":keys[i], "mb":disks[keys[i]].free_mb}); | |
| 156 } | |
| 157 // Sort these so the biggest disk comes first. | |
| 158 bot.disks.sort(function(a, b) { | |
| 159 return b.mb - a.mb; | |
| 160 }); | |
| 161 } | |
| 162 | |
| 163 bot.dimensions = bot.dimensions || []; | |
| 164 bot.dimensions.forEach(function(dim) { | |
| 165 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(dim.key) !== -1) { | |
| 166 dim.value.forEach(function(value, i){ | |
| 167 dim.value[i] = swarming.alias.apply(value, dim.key); | |
| 168 }); | |
| 169 } | |
| 170 }); | |
| 171 | |
| 172 BOT_TIMES.forEach(function(time) { | |
| 173 if (bot[time]) { | |
| 174 bot[time] = new Date(bot[time]); | |
| 175 bot["human_"+time] = formatDate(bot[time]); | |
| 176 } | |
| 177 }); | |
| 178 return bot; | |
| 179 }, | |
| 180 | |
| 181 parseEvents: function(events) { | |
| 182 if (!events || !events.items) { | |
| 183 return []; | |
| 184 } | |
| 185 var events = events.items; | |
| 186 events.forEach(function(event){ | |
| 187 // Do any preprocessing here | |
| 188 if (event.ts) { | |
| 189 event.ts = new Date(event.ts); | |
| 190 event.human_ts = formatDate(event.ts); | |
| 191 } | |
| 192 }); | |
| 193 | |
| 194 // Sort the most recent events first. | |
| 195 events.sort(function(a,b) { | |
| 196 return b.ts - a.ts; | |
| 197 }); | |
| 198 | |
| 199 return events; | |
| 200 }, | |
| 201 | |
| 202 parseTasks: function(tasks) { | |
| 203 if (!tasks || !tasks.items) { | |
| 204 return []; | |
| 205 } | |
| 206 var tasks = tasks.items; | |
| 207 | |
| 208 tasks.forEach(function(task){ | |
| 209 // Do any preprocessing here | |
| 210 TASK_TIMES.forEach(function(time) { | |
| 211 if (task[time]) { | |
| 212 task[time] = new Date(task[time]); | |
| 213 task["human_"+time] = formatDate(task[time]); | |
| 214 } | |
| 215 }); | |
| 216 | |
| 217 if (task.duration) { | |
| 218 task.human_duration = this._humanDuration(task.duration); | |
| 219 } else { | |
| 220 var end = task.completed_ts || task.abandoned_ts || task.modified_ts
|| new Date(); | |
| 221 task.human_duration = this._timeDiffExact(task.started_ts, end); | |
| 222 task.duration = (end.getTime() - task.started_ts) / 1000; | |
| 223 } | |
| 224 | |
| 225 task.state = task.state || "UNKNOWN"; | |
| 226 if (task.state === "COMPLETED") { | |
| 227 if (task.failure) { | |
| 228 task.state = "FAILURE"; | |
| 229 } else { | |
| 230 task.state = "SUCCESS"; | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 }.bind(this)); | |
| 235 | |
| 236 // Sort the most recent tasks first. | |
| 237 tasks.sort(function(a,b) { | |
| 238 return b.started_ts - a.started_ts; | |
| 239 }); | |
| 240 | |
| 241 return tasks; | |
| 242 } | |
| 243 | |
| 244 }); | |
| 245 })(); | |
| 246 </script> | |
| 247 </dom-module> | |
| OLD | NEW |