Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: appengine/swarming/elements/res/imp/botlist/bot-list-data.html

Issue 2408743002: Move elements/ to ui/ (Closed)
Patch Set: rebase again Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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-list-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 Usage:
15
16 <bot-list-data></bot-list-data>
17
18 Properties:
19 // inputs
20 auth_headers: Object, the OAuth2 header to include in the request. This
21 should come from swarming-app.
22
23 // outputs
24 bots: Array<Object>, all bots returned by the server. This is an Object
25 with at least the following structure:
26 dimensions: Array<Object>: Has key:String and value:Array<String>
27 task_id: String
28 external_ip: String
29 is_dead: Object: Is usually Boolean, but could be message string
30 quarantined: Object: Is usually Boolean, but could be message string
31 bot_id: String
32 state: String, Stringified JSON that has many pieces of information, like
33 devices, disk space, temperature, etc.
34 busy: Boolean, if any ajax requests are in flight.
35 dimensions: Array<String>, of all valid dimensions.
36 fleet: Object, counts of all bots in the fleet. Contains "alive", "busy",
37 "idle", "dead", and "quarantined".
38 primary_map: Object, a mapping of primary keys to secondary items.
39 The primary keys are things that can be columns or sorted by. The
40 primary values (aka the secondary items) are things that can be filtered
41 on. Primary consists of dimensions and state. Secondary contains the
42 values primary things can be.
43 primary_arr: Array<String>, the display order of the primary keys.
44 This is dimensions, then bot properties, then elements from bot.state.
45
46 Methods:
47 signIn(): Force a signin of the user using OAuth. This happens
48 automatically when auth_headers is set.
49
50 Events:
51 None.
52 -->
53
54 <link rel="import" href="bot-list-shared-behavior.html">
55
56 <dom-module id="bot-list-data">
57
58 <script>
59 (function(){
60 var AVAILABLE = "available";
61 var BLACKLIST_DIMENSIONS = ["quarantined", "error"];
62
63 function aggregateTemps(temps) {
64 if (!temps) {
65 return {};
66 }
67 var zones = [];
68 var avg = 0;
69 for (k in temps) {
70 zones.push(k +": "+temps[k]);
71 avg += temps[k];
72 }
73 avg = avg / zones.length
74 if (avg) {
75 avg = avg.toFixed(1);
76 } else {
77 avg = "unknown";
78 }
79 return {
80 average: avg,
81 zones: zones.join(" | ") || "unknown",
82 }
83 }
84
85 Polymer({
86 is: 'bot-list-data',
87
88 behaviors: [
89 SwarmingBehaviors.BotListBehavior,
90 ],
91
92 properties: {
93 // inputs
94 auth_headers: {
95 type: Object,
96 observer: "signIn",
97 },
98
99 //outputs
100 bots: {
101 type: Array,
102 computed: "parseBots(_list)",
103 notify: true,
104 },
105 busy: {
106 type: Boolean,
107 computed: "_or(_busy2,_busy1)",
108 notify: true,
109 },
110 dimensions: {
111 type: Array,
112 computed: "_makeArray(_dimensions)",
113 notify: true,
114 },
115 fleet: {
116 type: Object,
117 computed: "_fleet(_count)",
118 notify: true,
119 },
120 primary_map: {
121 type: Object,
122 computed: "_primaryMap(_dimensions)",
123 notify: true,
124 },
125 primary_arr: {
126 type: Array,
127 //BOT_PROPERTIES is inherited from BotListBehavior
128 computed: "_primaryArr(dimensions, BOT_PROPERTIES)",
129 notify: true,
130 },
131
132 // private
133 _busy1: {
134 type: Boolean,
135 value: false
136 },
137 _busy2: {
138 type: Boolean,
139 value: false
140 },
141 _count: {
142 type: Object,
143 },
144 _dimensions: {
145 type: Object,
146 },
147 _list: {
148 type: Object,
149 },
150 },
151
152 signIn: function(){
153 this._getJsonAsync("_count", "/_ah/api/swarming/v1/bots/count",
154 "_busy2", this.auth_headers);
155 this._getJsonAsync("_dimensions","/_ah/api/swarming/v1/bots/dimensions",
156 "_busy1", this.auth_headers);
157 },
158
159 parseBots: function(json){
160 if (!json || !json.items) {
161 return [];
162 }
163 // Do any preprocessing here
164 json.items.forEach(function(bot){
165 // Parse the state, which is a JSON string. This contains a lot of
166 // interesting information like details about the devices attached.
167 bot.state = bot.state || "{}";
168 bot.state = JSON.parse(bot.state) || {};
169 // get the disks in an easier to deal with format, sorted by size.
170 var disks = bot.state.disks || {};
171 var keys = Object.keys(disks);
172 if (!keys.length) {
173 bot.disks = [{"id": "unknown", "mb": 0}];
174 } else {
175 bot.disks = [];
176 for (var i = 0; i < keys.length; i++) {
177 bot.disks.push({"id":keys[i], "mb":disks[keys[i]].free_mb});
178 }
179 // Sort these so the biggest disk comes first.
180 bot.disks.sort(function(a, b) {
181 return b.mb - a.mb;
182 });
183 }
184
185 // Make sure every bot has a state.temp object and precompute
186 // average and list of temps by zone if applicable.
187 bot.state.temp = aggregateTemps(bot.state.temp);
188
189 var devices = [];
190 var d = (bot && bot.state && bot.state.devices) || {};
191 // state.devices is like {Serial:Object}, so we need to keep the seria l
192 for (key in d) {
193 var o = d[key];
194 o.serial = key;
195 o.okay = (o.state === AVAILABLE);
196 // It is easier to assume all devices on a bot are of the same type
197 // than to pick through the (incomplete) device state and find it.
198 // Bots that are quarentined because they have no devices
199 // still have devices in their state (the last known device attached )
200 // but don't have the device_type dimension. In that case, we punt
201 // on device type.
202 var types = this._dimension(bot, "device_type") || ["unknown"];
203 o.device_type = types[0];
204 o.temp = aggregateTemps(o.temp);
205 devices.push(o);
206 }
207 bot.state.devices = devices;
208
209 if (bot.last_seen_ts) {
210 bot.last_seen_ts = new Date(bot.last_seen_ts);
211 }
212 if (bot.first_seen_ts) {
213 bot.first_seen_ts = new Date(bot.first_seen_ts);
214 }
215 if (bot.lease_expiration_ts) {
216 bot.lease_expiration_ts = new Date(bot.lease_expiration_ts);
217 }
218
219 }.bind(this));
220 return json.items;
221 },
222
223 _fleet: function() {
224 if (!this._count) {
225 return {};
226 }
227 return {
228 all: this._count.count || -1,
229 alive: (this._count.count - this._count.dead) || -1,
230 busy: this._count.busy || -1,
231 idle: (this._count.count - this._count.busy) || -1,
232 dead: this._count.dead || -1,
233 quarantined: this._count.quarantined || -1,
234 }
235 },
236
237 _makeArray: function(dimObj) {
238 if (!dimObj || !dimObj.bots_dimensions) {
239 return [];
240 }
241 var dims = [];
242 dimObj.bots_dimensions.forEach(function(d){
243 if (BLACKLIST_DIMENSIONS.indexOf(d.key) === -1) {
244 dims.push(d.key);
245 }
246 });
247 dims.push("id");
248 dims.sort();
249 return dims;
250 },
251
252 _primaryArr: function(dimensions, properties) {
253 return dimensions.concat(properties);
254 },
255
256 _primaryMap: function(dimensions){
257 // pMap will have a list of columns to available values (primary key
258 // to secondary values). This includes bot dimensions, but also
259 // includes state like disk_space, quarantined, busy, etc.
260 dimensions = dimensions.bots_dimensions;
261
262 var pMap = {};
263 dimensions.forEach(function(d){
264 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(d.key) === -1) {
265 // value is an array of all seen values for the dimension d.key
266 pMap[d.key] = d.value;
267 } else {
268 var aliased = [];
269 d.value.forEach(function(value){
270 aliased.push(swarming.alias.apply(value, d.key));
271 });
272 pMap[d.key] = aliased;
273 }
274 });
275
276 // Add some options that might not show up.
277 pMap["android_devices"].push("0");
278 pMap["device_os"].push("none");
279 pMap["device_type"].push("none");
280
281 pMap["id"] = [];
282
283 // Create custom filter options
284 pMap["disk_space"] = [];
285 pMap["task"] = ["busy", "idle"];
286 pMap["status"] = ["alive", "dead", "quarantined"];
287
288 // No need to sort any of this, bot-filters sorts secondary items
289 // automatically, especially when the user types a query.
290 return pMap;
291 },
292
293 });
294 })();
295 </script>
296 </dom-module>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698