| Index: appengine/swarming/ui/build/elements.html
|
| diff --git a/appengine/swarming/ui/build/elements.html b/appengine/swarming/ui/build/elements.html
|
| index 8907d673034762ca4655970f8f49e8ecf5afdec2..48836c86b518f959e4e097e4717d511cf2c8f6c2 100644
|
| --- a/appengine/swarming/ui/build/elements.html
|
| +++ b/appengine/swarming/ui/build/elements.html
|
| @@ -962,4 +962,4 @@ the fleet."> <template is="dom-repeat" items="[[_filters]]" as="fil"> <div class
|
| }
|
|
|
| });
|
| - })(); </script> </dom-module><dom-module id="interval-timer" assetpath="/res/imp/common/"> <script>!function(){Polymer({is:"interval-timer",properties:{period:{type:Number,value:-1,observer:"_periodChanged"}},_periodChanged:function(e){this._timeout&&window.clearTimeout(this._timeout),e>0&&(this._timeout=window.setTimeout(function(){this.fire("trigger"),this._periodChanged(e)}.bind(this),1e3*e))}})}()</script> </dom-module> <dom-module id="task-page-data" assetpath="/res/imp/taskpage/"> <script>!function(){var t,e=400,s=["abandoned_ts","completed_ts","created_ts","modified_ts","started_ts"];Polymer({is:"task-page-data",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},task_id:{type:String},busy:{type:Boolean,computed:"_or(_busy1,_busy2,_busy3)",notify:!0},request:{type:Object,computed:"_parseRequest(_request)",notify:!0},result:{type:Object,computed:"_parseResult(_result)",notify:!0},stdout:{type:String,computed:"_parseStdout(_stdout)",notify:!0},task_exists:{type:Boolean,value:!0,notify:!0},_busy1:{type:Boolean,value:!1},_busy2:{type:Boolean,value:!1},_busy3:{type:Boolean,value:!1},_request:{type:Object},_result:{type:Object},_stdout:{type:Object}},observers:["reload(auth_headers,task_id)"],reload:function(){if(!this.task_id||!this.auth_headers)return void console.log("task_id and auth_headers can't be empty");t&&this.cancelAsync(t);var s="/api/swarming/v1/task/"+this.task_id;t=this.async(function(){t=void 0;var e=this._getJsonAsync("_request",s+"/request","_busy1",this.auth_headers);e.then(function(){this.set("task_exists",!0)}.bind(this)).catch(function(t){404===t.status?this.set("task_exists",!1):sk.errorMessage("Http response: "+(t.status||" ")+" "+t.response)}.bind(this)),this._getJsonAsync("_result",s+"/result?include_performance_stats=true","_busy2",this.auth_headers),this.reloadStdout()},e)},_parseRequest:function(t){return t?(t.tagMap={},t.tags=t.tags||[],t.tags.forEach(function(e){var s=e.split(":",1),a=s[0],u=e.substring(a.length+1);t.tagMap[a]=u}),s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),t):{}},_parseResult:function(t){if(!t)return{};var e=new Date;return s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),!t.duration&&t.state===this.RUNNING&&t.started_ts&&(t.duration=(e-t.started_ts)/1e3),t.duration&&(t.human_duration=this._humanDuration(t.duration)),t},_parseStdout:function(t){return t&&t.output?t.output:""},reloadStdout:function(){this._getJsonAsync("_stdout","/api/swarming/v1/task/"+this.task_id+"/stdout","_busy3",this.auth_headers)}})}()</script> </dom-module><dom-module id="task-disambiguation" assetpath="/res/imp/taskpage/"> <template> <style include="swarming-app-style single-page-style task-style"></style> <table> <thead> <tr> <th>Try ID</th> <th>Bot ID</th> <th>Status</th> </tr> </thead> <tbody> <template id="result_list" is="dom-repeat" items="[[_results]]" as="result" observe="task_id bot_id state"> <tr> <td> <a href$="[[_taskLink(result.task_id,'true')]]"> [[result.task_id]] </a> </td> <td> <a href$="[[_botLink(result.bot_id)]]"> [[result.bot_id]] </a> </td> <td class$="[[_stateClass(result)]]">[[state(result)]]</td> </tr> </template> </tbody> </table> </template> <script>Polymer({is:"task-disambiguation",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},summary_result:{type:Object},task_id:{type:String},busy:{type:Boolean,value:!1,notify:!0},_busyArr:{type:Array,value:function(){return[]}},_results:{type:Array,value:function(){return[]}}},observers:["_fetchRest(auth_headers,task_id,summary_result)","_computeBusy(_busyArr.*)"],_computeBusy:function(){for(var s=0;s<this._busyArr.length;s++)if(this._busyArr[s].status)return!0;return!1},_fetchRest:function(s,r,t){if(s&&r&&t){var e=t.try_number;this.set("_busyArr",[]),this.set("_results",[]);for(var u=r.substring(0,r.length-1),i="/api/swarming/v1/task/",a=0;a<e-1;a++){var n=u+(a+1);this.splice("_busyArr",a,0,{}),this.splice("_results",a,0,{task_id:n}),this._getJsonAsyncArr(a,"_results",i+n+"/result","_busyArr",s)}t.task_id=u+e,this.splice("_results",e-1,1,t)}}})</script> </dom-module><dom-module id="task-page" assetpath="/res/imp/taskpage/"> <template> <style include="iron-flex iron-flex-alignment swarming-app-style single-page-style task-style">.milo{width:calc(100% - 11px);height:2000px}.left{min-width:550px}.right{min-width:500px;margin-top:8px}.expand{min-width:3em;vertical-align:middle;padding:.5em}.code{font-family:monospace}.stdout{white-space:pre-line;padding:2px}.refresh_input{padding:0 5px}.reproduce{margin-left:5px}.tabbed{border:3px solid #1F78B4;margin-left:5px;min-height:80vh}</style> <url-param name="id" value="{{task_id}}"> </url-param> <url-param name="try_detail" value="{{_try_detail}}"> </url-param> <url-param name="request_detail" value="{{_request_detail}}"> </url-param> <url-param name="show_raw" value="{{_show_raw}}"> </url-param> <url-param name="refresh" value="{{_refresh_interval}}" default_value="10"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" profile="{{_profile}}" server_details="{{_server_details}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,busy2)]]" name="Swarming Task Page"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <task-page-data id="data" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" busy="{{_busy1}}" request="{{_request}}" result="{{_result}}" stdout="{{_stdout}}" task_exists="{{_task_exists}}"> </task-page-data> <div class="horizontal layout wrap"> <div class="left flex"> <div class="horizontal layout"> <paper-input class="id_input" label="Task id" value="{{task_id}}"></paper-input> <button on-click="_refresh"> <iron-icon class="refresh" icon="icons:refresh"></iron-icon> </button> <button on-click="_promptRetry">Retry</button> <template is="dom-if" if="[[_canCancelTask(_result,_permissions)]]"> <button on-click="_promptCancel">Cancel</button> </template> </div> <h2 hidden$="[[_task_exists]]">Task not found.</h2> <template is="dom-if" if="[[_disambiguate(task_id,_result)]]"> <h2>Displaying a summary for a task with multiple tries</h2> <task-disambiguation busy="{{busy2}}" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" summary_result="[[_result]]"> </task-disambiguation> </template> <table hidden$="[[_not(_task_exists)]]"> <tbody><tr> <td>Name</td> <td>[[_request.name]]</td> </tr> <tr> <td>State</td> <td class$="[[_stateClass(_result)]]">[[state(_result)]]</td> </tr> <tr> <td>Created</td> <td title$="[[_request.created_ts]]">[[_request.human_created_ts]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>Started</td> <td title$="[[_result.started_ts]]">[[_result.human_started_ts]]</td> </tr> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> <tr> <td>Expires</td> <td>[[_expires(_request)]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_completed_ts]]"> <tr> <td>Completed</td> <td title$="[[_result.completed_ts]]">[[_result.human_completed_ts]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_abandoned_ts]]"> <tr> <td>Abandoned</td> <td title$="[[_result.abandoned_ts]]">[[_result.human_abandoned_ts]]</td> </tr> </template> <tr> <td>Last Updated</td> <td title$="[[_result.modified_ts]]">[[_result.human_modified_ts]]</td> </tr> <template is="dom-if" if="[[_result.deduped_from]]"> <tr> <td><b>Deduped from</b></td> <td> <a href$="[[_taskLink(_result.deduped_from)]]"> [[_result.deduped_from]] </a> </td> </tr> </template> <tr> <td>Pending Time</td> <td>[[_pending(_result)]]</td> </tr> <tr> <td>Duration</td> <td>[[_result.human_duration]]</td> </tr> <tr> <td>Priority</td> <td>[[_request.priority]]</td> </tr> <tr> <td>User</td> <td>[[_request.user]]</td> </tr> <tr> <td>Authenticated</td> <td>[[_request.authenticated]]</td> </tr> <template is="dom-if" if="[[_request.service_account]]"> <tr> <td>Service Account</td> <td>[[_request.service_account]]</td> </tr> </template> <template is="dom-if" if="[[_request.properties.secret_bytes]]"> <tr> <td>Secret Bytes</td> <td>[[_request.properties.secret_bytes]]</td> </tr> </template> <template is="dom-if" if="[[_request.parent_task_id]]"> <tr> <td>Parent Task</td> <td> <a href$="[[_taskLink(_request.parent_task_id)]]">[[_request.parent_task_id]]</a> </td> </tr> </template> <tr> <td rowspan$="[[_rowspan(_request.properties.dimensions)]]"> <a title="The list of bots that matches the list of dimensions" href$="[[_botListLink(_request.properties.dimensions)]]"> Requested Dimensions </a> </td> </tr> <template is="dom-repeat" items="{{_request.properties.dimensions}}" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Isolated Inputs</td> <td> <a href$="[[_isolateLink(_request.properties.inputs_ref)]]"> [[_request.properties.inputs_ref.isolated]] </a> </td> </tr> <template is="dom-if" if="[[_request.properties.outputs.length]]"> <tr> <td rowspan$="[[_rowspan(_request.properties.outputs)]]">Expected outputs</td> </tr> <template is="dom-repeat" items="{{_request.properties.outputs}}" as="output"> <tr> <td>[[output]]</td> </tr> </template> </template> <template is="dom-if" if="[[_not(_request_detail)]]"> <tr> <td>More Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:add-circle-outline"></iron-icon> </button> </td> </tr> </template> <template is="dom-if" if="[[_request_detail]]"> <tr> <td>Hide Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:remove-circle-outline"></iron-icon> </button> </td> </tr> </template> <template is="dom-if" if="[[_request_detail]]"> <tr> <td>Extra Args</td> <td class="code">[[_extraArgs(_request)]]</td> </tr> <tr> <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td> </tr> <template is="dom-repeat" items="{{_request.tags}}" as="tag"> <tr> <td>[[tag]]</td> </tr> </template> <tr> <td>Execution timeout</td> <td>[[_humanDuration(_request.properties.execution_timeout_secs)]]</td> </tr> <tr> <td>I/O timeout</td> <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</td> </tr> <tr> <td>Grace period</td> <td>[[_humanDuration(_request.properties.grace_period_secs)]]</td> </tr> <tr> <td>CIPD server</td> <td> <a href$="[[_request.properties.cipd_input.server]]"> [[_request.properties.cipd_input.server]] </a> </td> </tr> <tr> <td>CIPD version</td> <td>[[_request.properties.cipd_input.client_package.version]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>CIPD package name</td> <td>[[_result.cipd_pins.client_package.package_name]]</td> </tr> </template> <tr hidden$="[[_not(_request.properties.cipd_input)]]"> <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD packages</td> </tr> <template is="dom-repeat" items="[[_cipdPackages(_request,_result)]]" as="cipd"> <tr> <td>[[cipd.path]]/</td> </tr> <tr> <td><b>Requested:</b>[[cipd.requested]]</td> </tr> <tr hidden$="[[_wasNotPickedUp(_result)]]"> <td><b>Actual:</b>[[cipd.actual]]</td> </tr> </template> <tr hidden$="[[_empty(_request.properties.caches)]]"> <td rowspan$="[[_rowspan(_request.properties.caches)]]">Named caches</td> </tr> <template is="dom-repeat" items="[[_request.properties.caches]]" as="cache"> <tr> <td><span>[[cache.name]]</span>:<span>[[cache.path]]</span></td> </tr> </template> </template> </tbody></table> <div class="title" hidden$="[[_not(_task_exists)]]">Task Execution</div> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <table hidden$="[[_not(_task_exists)]]"> <tbody><tr> <td>Bot assigned to task</td> <td><a href$="[[_botLink(_result.bot_id)]]">[[_result.bot_id]]</a></td> </tr> <tr> <td rowspan$="[[_rowspan(_result.bot_dimensions)]]"> <a>Bot Dimensions</a> </td> </tr> <template is="dom-repeat" items="[[_result.bot_dimensions]]" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Exit code</td> <td>[[_result.exit_code]]</td> </tr> <tr> <td>Try number</td> <td>[[_result.try_number]]</td> </tr> <tr> <td>Failure</td> <td class$="[[_failureClass(_result.failure)]]">[[_result.failure]]</td> </tr> <tr> <td>Internal Failure</td> <td class$="[[_internalClass(_result.internal_failure)]]">[[_result.internal_failure]]</td> </tr> <tr> <td>Isolated Outputs</td> <td> <a href$="[[_isolateLink(_result.outputs_ref)]]"> [[_result.outputs_ref.isolated]] </a> </td> </tr> <tr> <td>Bot version</td> <td>[[_result.bot_version]]</td> </tr> <tr> <td>Server version</td> <td>[[_result.server_versions]]</td> </tr> </tbody></table> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> This space left blank until a bot is assigned to the task. </template> <template is="dom-if" if="[[_result.performance_stats]]"> <div class="title">Performance Stats</div> <table> <tbody><tr> <td title="This includes time taken to download inputs, isolate outputs, and setup CIPD">Total Overhead</td> <td>[[_humanDuration(_result.performance_stats.bot_overhead)]]</td> </tr> <tr> <td>Downloading Inputs From Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_download.duration)]]</td> </tr> <tr> <td>Uploading Outputs To Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_upload.duration)]]</td> </tr> <tr> <td>Initial bot cache</td> <td>[[_result.performance_stats.isolated_download.initial_number_items]] items; [[_bytes(_result.performance_stats.isolated_download.initial_size)]]</td> </tr> </tbody></table> </template> <div class="title">Reproducing the task locally</div> <div class="reproduce"> <div>Download inputs files into directory <i>foo</i>:</div> <div class="code"> python isolateserver.py download -I [[_request.properties.inputs_ref.isolatedserver]] --namespace [[_request.properties.inputs_ref.namespace]] -s [[_request.properties.inputs_ref.isolated]] --target foo</div> <br> <div>Run this task locally:</div> <div class="code"> python swarming.py reproduce -S [[_host_url]] [[task_id]]</div> <br> <div>Download output results into directory <i>foo</i>:</div> <div class="code"> python swarming.py collect -S [[_host_url]] --task-output-dir=foo [[task_id]]</div> <br> <div>Looking for <i>swarming.py</i>?</div> <div class="code"> git clone https://github.com/luci/client-py</div> </div> </div> <div class="flex right" hidden$="[[_not(_task_exists)]]"> <div class="horizontal layout"> <div class="tabs"> <paper-tabs selected="{{_show_raw}}" no-bar=""> <paper-tab disabled$="[[_noMilo(_request)]]">Milo Output</paper-tab> <paper-tab>Raw Output</paper-tab> </paper-tabs> </div> <paper-input class="refresh_input" label="Refresh Interval (seconds)" value="{{_refresh_interval}}" title="How often to refresh all information about the task" auto-validate="" min="1" max="1000" pattern="[0-9]+"> </paper-input> </div> <template is="dom-if" if="[[_supportsMilo(_request,_show_raw)]]"> <div class="milo tabbed" hidden$="[[_isSummaryLink(task_id)]]"> Milo results are only generated for task summaires, that is, tasks whose ids end in 0. Tasks ending in 1 or 2 represent possible retries of tasks. See <a href="//goo.gl/LE4rwV">the docs</a> for more. </div> <iframe id="miloFrame" class="milo tabbed" src$="[[_getDisplayServerLink(_server_details.display_server_url_template,task_id)]]"></iframe> </template> <template is="dom-if" if="[[_show_raw]]"> <div class="code stdout tabbed">[[_rawOutput(_stdout,_result)]]</div> </template> </div> </div> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialog_prompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> <interval-timer period="[[_refresh_interval]]" on-trigger="_softRefresh"> </interval-timer> </template> <script>!function(){Polymer({is:"task-page",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{task_id:{type:String},client_id:{type:String},_dialog_prompt:{type:String,value:""},_host_url:{type:String,value:function(){return window.location.hostname}},_refresh_interval:{type:Number},_request:{type:Object,observer:"_requestUpdated"},_request_detail:{type:Boolean},_result:{type:Object},_server_details:{type:Object},_stdout:{type:String}},_alias:function(t){var e=t.value;return Array.isArray(e)||(e=[e]),swarming.alias.has(t.key)&&e.forEach(function(i,s){e[s]=swarming.alias.apply(i,t.key)}),e.join(" | ")},_bytes:function(t){return sk.human.bytes(t)},_canCancelTask:function(t,e){return t&&"PENDING"===t.state&&e.cancel_task},_cancelTask:function(){var t="/api/swarming/v1/task/"+this.task_id+"/cancel";swarming.postWithToast(t,"Canceling task "+this.task_id,this._auth_headers)},_cipdRowspan:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return 0;var i=(t.properties.cipd_input.packages||[]).length;return i*=e&&e.cipd_pins&&e.cipd_pins.packages?3:2,i+1},_cipdPackages:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return[];var i=t.properties.cipd_input.packages||[],s=e&&e.cipd_pins&&e.cipd_pins.packages||[];return i.forEach(function(t){t.requested=t.package_name+":"+t.version,s.forEach(function(e){e.path===t.path&&(t.actual=e.package_name+":"+e.version)})}),i},_disambiguate:function(t,e){return!(!t.endsWith("0")||!e)&&e.try_number>1},_empty:function(t){return!t||0==t.length},_expires:function(t){var e=parseInt(t.expiration_secs);return e?sk.human.localeTime(new Date(t.created_ts.getTime()+1e3*e)):t.expiration_secs+" seconds from created time"},_extraArgs:function(t){if(!t||!t.properties)return"";var e=t.properties.extra_args||[];return e.join(" ")},_failureClass:function(t){return t?"failed_task":""},_getDisplayServerLink:function(t,e){if(t)return t.replace("%s",e)},_internalClass:function(t){return t?"exception":""},_isolateLink:function(t){if(t&&t.isolatedserver)return t.isolatedserver+"/browse?namespace="+t.namespace+"&hash="+t.isolated},_isSummaryLink:function(t){return t&&t.endsWith(0)},_noMilo:function(t){return!this._tag(t,"allow_milo")},_pending:function(t){if(!t.created_ts)return"";var e=t.started_ts||t.abandoned_ts||new Date;return e<=t.created_ts?"0s":this._timeDiffExact(t.created_ts,e)},_promptClosed:function(t){t.detail.confirmed&&(this._dialog_prompt.startsWith("cancel")?this._cancelTask():this._retryTask())},_promptCancel:function(){this.set("_dialog_prompt","cancel task "+this.task_id),this.$.prompt.open()},_promptRetry:function(){this.set("_dialog_prompt","retry task "+this.task_id),this.$.prompt.open()},_rawOutput:function(t,e){return t?t:"PENDING"===e.state||"RUNNING"===e.state?"[No output yet]":"[No output received]"},_refresh:function(){this.$.data.reload()},_requestUpdated:function(t){this._noMilo(t)&&this.set("_show_raw",1)},_softRefresh:function(){if(!this._result||"RUNNING"===this._result.state||"PENDING"===this._result.state){this.$.data.reload();var t=this.$$("iframe");t&&(t.src=this._getDisplayServerLink(this._server_details.display_server_url_template,this.task_id))}},_retryTask:function(){if(!this._request)return void sk.errorMessage("Task not yet loaded",3e3);var t={expiration_secs:this._request.expiration_secs,name:this._request.name+" (retry)",parent_task_id:this._request.parent_task_id,priority:this._request.priority,properties:this._request.properties,tags:this._request.tags,user:this._profile.email,service_account:this._request.service_account};swarming.postWithToast("/api/swarming/v1/tasks/new","Retrying task "+this.task_id,this._auth_headers,t).then(function(t){t=JSON.parse(t),t&&t.task_id&&this.set("task_id",t.task_id)}.bind(this),function(t){console.log("Task could not be retried",t)})},_rowspan:function(t){return t=t||[],t.length+1},_supportsMilo:function(t,e){return!e&&t&&this._tag(t,"allow_milo")},_toggleDetails:function(){this.set("_request_detail",!this._request_detail)},_tag:function(t,e){if(t&&t.tagMap)return t.tagMap[e]},_wasPickedUp:function(t){return t&&t.state!==this.PENDING&&t.state!==this.CANCELED&&t.state!=this.EXPIRED},_wasNotPickedUp:function(t){return t&&!this._wasPickedUp(t)}})}()</script> </dom-module> </div></body></html>
|
| + })(); </script> </dom-module><dom-module id="interval-timer" assetpath="/res/imp/common/"> <script>!function(){Polymer({is:"interval-timer",properties:{period:{type:Number,value:-1,observer:"_periodChanged"}},_periodChanged:function(e){this._timeout&&window.clearTimeout(this._timeout),e>0&&(this._timeout=window.setTimeout(function(){this.fire("trigger"),this._periodChanged(e)}.bind(this),1e3*e))}})}()</script> </dom-module> <dom-module id="task-page-data" assetpath="/res/imp/taskpage/"> <script>!function(){var t,e=400,s=["abandoned_ts","completed_ts","created_ts","modified_ts","started_ts"];Polymer({is:"task-page-data",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},task_id:{type:String},busy:{type:Boolean,computed:"_or(_busy1,_busy2,_busy3)",notify:!0},request:{type:Object,computed:"_parseRequest(_request)",notify:!0},result:{type:Object,computed:"_parseResult(_result)",notify:!0},stdout:{type:String,computed:"_parseStdout(_stdout)",notify:!0},task_exists:{type:Boolean,value:!0,notify:!0},_busy1:{type:Boolean,value:!1},_busy2:{type:Boolean,value:!1},_busy3:{type:Boolean,value:!1},_request:{type:Object},_result:{type:Object},_stdout:{type:Object}},observers:["reload(auth_headers,task_id)"],reload:function(){if(!this.task_id||!this.auth_headers)return void console.log("task_id and auth_headers can't be empty");t&&this.cancelAsync(t);var s="/api/swarming/v1/task/"+this.task_id;t=this.async(function(){t=void 0;var e=this._getJsonAsync("_request",s+"/request","_busy1",this.auth_headers);e.then(function(){this.set("task_exists",!0)}.bind(this)).catch(function(t){404===t.status?this.set("task_exists",!1):sk.errorMessage("Http response: "+(t.status||" ")+" "+t.response)}.bind(this)),this._getJsonAsync("_result",s+"/result?include_performance_stats=true","_busy2",this.auth_headers),this.reloadStdout()},e)},_parseRequest:function(t){return t?(t.tagMap={},t.tags=t.tags||[],t.tags.forEach(function(e){var s=e.split(":",1),a=s[0],u=e.substring(a.length+1);t.tagMap[a]=u}),s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),t):{}},_parseResult:function(t){if(!t)return{};var e=new Date;return s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),!t.duration&&t.state===this.RUNNING&&t.started_ts&&(t.duration=(e-t.started_ts)/1e3),t.duration&&(t.human_duration=this._humanDuration(t.duration)),t},_parseStdout:function(t){return t&&t.output?t.output:""},reloadStdout:function(){this._getJsonAsync("_stdout","/api/swarming/v1/task/"+this.task_id+"/stdout","_busy3",this.auth_headers)}})}()</script> </dom-module><dom-module id="task-disambiguation" assetpath="/res/imp/taskpage/"> <template> <style include="swarming-app-style single-page-style task-style"></style> <table> <thead> <tr> <th>Try ID</th> <th>Bot ID</th> <th>Status</th> </tr> </thead> <tbody> <template id="result_list" is="dom-repeat" items="[[_results]]" as="result" observe="task_id bot_id state"> <tr> <td> <a href$="[[_taskLink(result.task_id,'true')]]"> [[result.task_id]] </a> </td> <td> <a href$="[[_botLink(result.bot_id)]]"> [[result.bot_id]] </a> </td> <td class$="[[_stateClass(result)]]">[[state(result)]]</td> </tr> </template> </tbody> </table> </template> <script>Polymer({is:"task-disambiguation",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},summary_result:{type:Object},task_id:{type:String},busy:{type:Boolean,value:!1,notify:!0},_busyArr:{type:Array,value:function(){return[]}},_results:{type:Array,value:function(){return[]}}},observers:["_fetchRest(auth_headers,task_id,summary_result)","_computeBusy(_busyArr.*)"],_computeBusy:function(){for(var s=0;s<this._busyArr.length;s++)if(this._busyArr[s].status)return!0;return!1},_fetchRest:function(s,r,t){if(s&&r&&t){var e=t.try_number;this.set("_busyArr",[]),this.set("_results",[]);for(var u=r.substring(0,r.length-1),i="/api/swarming/v1/task/",a=0;a<e-1;a++){var n=u+(a+1);this.splice("_busyArr",a,0,{}),this.splice("_results",a,0,{task_id:n}),this._getJsonAsyncArr(a,"_results",i+n+"/result","_busyArr",s)}t.task_id=u+e,this.splice("_results",e-1,1,t)}}})</script> </dom-module><dom-module id="task-page" assetpath="/res/imp/taskpage/"> <template> <style include="iron-flex iron-flex-alignment swarming-app-style single-page-style task-style">.milo{width:calc(100% - 11px);height:2000px}.left{min-width:550px}.right{min-width:500px;margin-top:8px}.expand{min-width:3em;vertical-align:middle;padding:.5em}.code{font-family:monospace}.stdout{white-space:pre-line;padding:2px}.refresh_input{padding:0 5px}.reproduce{margin-left:5px}.tabbed{border:3px solid #1F78B4;margin-left:5px;min-height:80vh}</style> <url-param name="id" value="{{task_id}}"> </url-param> <url-param name="try_detail" value="{{_try_detail}}"> </url-param> <url-param name="request_detail" value="{{_request_detail}}"> </url-param> <url-param name="show_raw" value="{{_show_raw}}"> </url-param> <url-param name="refresh" value="{{_refresh_interval}}" default_value="10"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" profile="{{_profile}}" server_details="{{_server_details}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,busy2)]]" name="Swarming Task Page"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <task-page-data id="data" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" busy="{{_busy1}}" request="{{_request}}" result="{{_result}}" stdout="{{_stdout}}" task_exists="{{_task_exists}}"> </task-page-data> <div class="horizontal layout wrap"> <div class="left flex"> <div class="horizontal layout"> <paper-input class="id_input" label="Task id" value="{{task_id}}"></paper-input> <button on-click="_refresh"> <iron-icon class="refresh" icon="icons:refresh"></iron-icon> </button> <button on-click="_promptRetry">Retry</button> <template is="dom-if" if="[[_canCancelTask(_result,_permissions)]]"> <button on-click="_promptCancel">Cancel</button> </template> </div> <h2 hidden$="[[_task_exists]]">Task not found.</h2> <template is="dom-if" if="[[_disambiguate(task_id,_result)]]"> <h2>Displaying a summary for a task with multiple tries</h2> <task-disambiguation busy="{{busy2}}" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" summary_result="[[_result]]"> </task-disambiguation> </template> <table hidden$="[[_not(_task_exists)]]"> <tbody><tr> <td>Name</td> <td>[[_request.name]]</td> </tr> <tr> <td>State</td> <td class$="[[_stateClass(_result)]]">[[state(_result)]]</td> </tr> <tr> <td>Created</td> <td title$="[[_request.created_ts]]">[[_request.human_created_ts]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>Started</td> <td title$="[[_result.started_ts]]">[[_result.human_started_ts]]</td> </tr> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> <tr> <td>Expires</td> <td>[[_expires(_request)]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_completed_ts]]"> <tr> <td>Completed</td> <td title$="[[_result.completed_ts]]">[[_result.human_completed_ts]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_abandoned_ts]]"> <tr> <td>Abandoned</td> <td title$="[[_result.abandoned_ts]]">[[_result.human_abandoned_ts]]</td> </tr> </template> <tr> <td>Last Updated</td> <td title$="[[_result.modified_ts]]">[[_result.human_modified_ts]]</td> </tr> <template is="dom-if" if="[[_result.deduped_from]]"> <tr> <td><b>Deduped from</b></td> <td> <a href$="[[_taskLink(_result.deduped_from)]]"> [[_result.deduped_from]] </a> </td> </tr> </template> <tr> <td>Pending Time</td> <td>[[_pending(_result)]]</td> </tr> <tr> <td>Duration</td> <td>[[_result.human_duration]]</td> </tr> <tr> <td>Priority</td> <td>[[_request.priority]]</td> </tr> <tr> <td>User</td> <td>[[_request.user]]</td> </tr> <tr> <td>Authenticated</td> <td>[[_request.authenticated]]</td> </tr> <template is="dom-if" if="[[_request.service_account]]"> <tr> <td>Service Account</td> <td>[[_request.service_account]]</td> </tr> </template> <template is="dom-if" if="[[_request.properties.secret_bytes]]"> <tr> <td>Secret Bytes</td> <td>[[_request.properties.secret_bytes]]</td> </tr> </template> <template is="dom-if" if="[[_request.parent_task_id]]"> <tr> <td>Parent Task</td> <td> <a href$="[[_taskLink(_request.parent_task_id)]]">[[_request.parent_task_id]]</a> </td> </tr> </template> <tr> <td rowspan$="[[_rowspan(_request.properties.dimensions)]]"> <a title="The list of bots that matches the list of dimensions" href$="[[_botListLink(_request.properties.dimensions)]]"> Requested Dimensions </a> </td> </tr> <template is="dom-repeat" items="{{_request.properties.dimensions}}" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Isolated Inputs</td> <td> <a href$="[[_isolateLink(_request.properties.inputs_ref)]]"> [[_request.properties.inputs_ref.isolated]] </a> </td> </tr> <template is="dom-if" if="[[_request.properties.outputs.length]]"> <tr> <td rowspan$="[[_rowspan(_request.properties.outputs)]]">Expected outputs</td> </tr> <template is="dom-repeat" items="{{_request.properties.outputs}}" as="output"> <tr> <td>[[output]]</td> </tr> </template> </template> <template is="dom-if" if="[[_not(_request_detail)]]"> <tr> <td>More Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:add-circle-outline"></iron-icon> </button> </td> </tr> </template> <template is="dom-if" if="[[_request_detail]]"> <tr> <td>Hide Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:remove-circle-outline"></iron-icon> </button> </td> </tr> </template> <template is="dom-if" if="[[_request_detail]]"> <tr> <td>Extra Args</td> <td class="code">[[_extraArgs(_request)]]</td> </tr> <tr> <td>Command</td> <td class="code">[[_command(_request)]]</td> </tr> <tr> <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td> </tr> <template is="dom-repeat" items="{{_request.tags}}" as="tag"> <tr> <td>[[tag]]</td> </tr> </template> <tr> <td>Execution timeout</td> <td>[[_humanDuration(_request.properties.execution_timeout_secs)]]</td> </tr> <tr> <td>I/O timeout</td> <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</td> </tr> <tr> <td>Grace period</td> <td>[[_humanDuration(_request.properties.grace_period_secs)]]</td> </tr> <tr> <td>CIPD server</td> <td> <a href$="[[_request.properties.cipd_input.server]]"> [[_request.properties.cipd_input.server]] </a> </td> </tr> <tr> <td>CIPD version</td> <td>[[_request.properties.cipd_input.client_package.version]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>CIPD package name</td> <td>[[_result.cipd_pins.client_package.package_name]]</td> </tr> </template> <tr hidden$="[[_not(_request.properties.cipd_input)]]"> <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD packages</td> </tr> <template is="dom-repeat" items="[[_cipdPackages(_request,_result)]]" as="cipd"> <tr> <td>[[cipd.path]]/</td> </tr> <tr> <td><b>Requested:</b>[[cipd.requested]]</td> </tr> <tr hidden$="[[_wasNotPickedUp(_result)]]"> <td><b>Actual:</b>[[cipd.actual]]</td> </tr> </template> <tr hidden$="[[_empty(_request.properties.caches)]]"> <td rowspan$="[[_rowspan(_request.properties.caches)]]">Named caches</td> </tr> <template is="dom-repeat" items="[[_request.properties.caches]]" as="cache"> <tr> <td><span>[[cache.name]]</span>:<span>[[cache.path]]</span></td> </tr> </template> </template> </tbody></table> <div class="title" hidden$="[[_not(_task_exists)]]">Task Execution</div> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <table hidden$="[[_not(_task_exists)]]"> <tbody><tr> <td>Bot assigned to task</td> <td><a href$="[[_botLink(_result.bot_id)]]">[[_result.bot_id]]</a></td> </tr> <tr> <td rowspan$="[[_rowspan(_result.bot_dimensions)]]"> <a>Bot Dimensions</a> </td> </tr> <template is="dom-repeat" items="[[_result.bot_dimensions]]" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Exit code</td> <td>[[_result.exit_code]]</td> </tr> <tr> <td>Try number</td> <td>[[_result.try_number]]</td> </tr> <tr> <td>Failure</td> <td class$="[[_failureClass(_result.failure)]]">[[_result.failure]]</td> </tr> <tr> <td>Internal Failure</td> <td class$="[[_internalClass(_result.internal_failure)]]">[[_result.internal_failure]]</td> </tr> <tr> <td>Isolated Outputs</td> <td> <a href$="[[_isolateLink(_result.outputs_ref)]]"> [[_result.outputs_ref.isolated]] </a> </td> </tr> <tr> <td>Bot version</td> <td>[[_result.bot_version]]</td> </tr> <tr> <td>Server version</td> <td>[[_result.server_versions]]</td> </tr> </tbody></table> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> This space left blank until a bot is assigned to the task. </template> <template is="dom-if" if="[[_result.performance_stats]]"> <div class="title">Performance Stats</div> <table> <tbody><tr> <td title="This includes time taken to download inputs, isolate outputs, and setup CIPD">Total Overhead</td> <td>[[_humanDuration(_result.performance_stats.bot_overhead)]]</td> </tr> <tr> <td>Downloading Inputs From Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_download.duration)]]</td> </tr> <tr> <td>Uploading Outputs To Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_upload.duration)]]</td> </tr> <tr> <td>Initial bot cache</td> <td>[[_result.performance_stats.isolated_download.initial_number_items]] items; [[_bytes(_result.performance_stats.isolated_download.initial_size)]]</td> </tr> </tbody></table> </template> <div class="title">Reproducing the task locally</div> <div class="reproduce"> <div>Download inputs files into directory <i>foo</i>:</div> <div class="code"> python isolateserver.py download -I [[_request.properties.inputs_ref.isolatedserver]] --namespace [[_request.properties.inputs_ref.namespace]] -s [[_request.properties.inputs_ref.isolated]] --target foo</div> <br> <div>Run this task locally:</div> <div class="code"> python swarming.py reproduce -S [[_host_url]] [[task_id]]</div> <br> <div>Download output results into directory <i>foo</i>:</div> <div class="code"> python swarming.py collect -S [[_host_url]] --task-output-dir=foo [[task_id]]</div> <br> <div>Looking for <i>swarming.py</i>?</div> <div class="code"> git clone https://github.com/luci/client-py</div> </div> </div> <div class="flex right" hidden$="[[_not(_task_exists)]]"> <div class="horizontal layout"> <div class="tabs"> <paper-tabs selected="{{_show_raw}}" no-bar=""> <paper-tab disabled$="[[_noMilo(_request)]]">Milo Output</paper-tab> <paper-tab>Raw Output</paper-tab> </paper-tabs> </div> <paper-input class="refresh_input" label="Refresh Interval (seconds)" value="{{_refresh_interval}}" title="How often to refresh all information about the task" auto-validate="" min="1" max="1000" pattern="[0-9]+"> </paper-input> </div> <template is="dom-if" if="[[_supportsMilo(_request,_show_raw)]]"> <div class="milo tabbed" hidden$="[[_isSummaryLink(task_id)]]"> Milo results are only generated for task summaires, that is, tasks whose ids end in 0. Tasks ending in 1 or 2 represent possible retries of tasks. See <a href="//goo.gl/LE4rwV">the docs</a> for more. </div> <iframe id="miloFrame" class="milo tabbed" src$="[[_getDisplayServerLink(_server_details.display_server_url_template,task_id)]]"></iframe> </template> <template is="dom-if" if="[[_show_raw]]"> <div class="code stdout tabbed">[[_rawOutput(_stdout,_result)]]</div> </template> </div> </div> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialog_prompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> <interval-timer period="[[_refresh_interval]]" on-trigger="_softRefresh"> </interval-timer> </template> <script>!function(){Polymer({is:"task-page",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{task_id:{type:String},client_id:{type:String},_dialog_prompt:{type:String,value:""},_host_url:{type:String,value:function(){return window.location.hostname}},_refresh_interval:{type:Number},_request:{type:Object,observer:"_requestUpdated"},_request_detail:{type:Boolean},_result:{type:Object},_server_details:{type:Object},_stdout:{type:String}},_alias:function(t){var e=t.value;return Array.isArray(e)||(e=[e]),swarming.alias.has(t.key)&&e.forEach(function(i,r){e[r]=swarming.alias.apply(i,t.key)}),e.join(" | ")},_bytes:function(t){return sk.human.bytes(t)},_canCancelTask:function(t,e){return t&&"PENDING"===t.state&&e.cancel_task},_cancelTask:function(){var t="/api/swarming/v1/task/"+this.task_id+"/cancel";swarming.postWithToast(t,"Canceling task "+this.task_id,this._auth_headers)},_cipdRowspan:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return 0;var i=(t.properties.cipd_input.packages||[]).length;return i*=e&&e.cipd_pins&&e.cipd_pins.packages?3:2,i+1},_cipdPackages:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return[];var i=t.properties.cipd_input.packages||[],r=e&&e.cipd_pins&&e.cipd_pins.packages||[];return i.forEach(function(t){t.requested=t.package_name+":"+t.version,r.forEach(function(e){e.path===t.path&&(t.actual=e.package_name+":"+e.version)})}),i},_command:function(t){if(!t||!t.properties)return"";var e=t.properties.command||[];return e.join(" ")},_disambiguate:function(t,e){return!(!t.endsWith("0")||!e)&&e.try_number>1},_empty:function(t){return!t||0==t.length},_expires:function(t){var e=parseInt(t.expiration_secs);return e?sk.human.localeTime(new Date(t.created_ts.getTime()+1e3*e)):t.expiration_secs+" seconds from created time"},_extraArgs:function(t){if(!t||!t.properties)return"";var e=t.properties.extra_args||[];return e.join(" ")},_failureClass:function(t){return t?"failed_task":""},_getDisplayServerLink:function(t,e){if(t)return t.replace("%s",e)},_internalClass:function(t){return t?"exception":""},_isolateLink:function(t){if(t&&t.isolatedserver)return t.isolatedserver+"/browse?namespace="+t.namespace+"&hash="+t.isolated},_isSummaryLink:function(t){return t&&t.endsWith(0)},_noMilo:function(t){return!this._tag(t,"allow_milo")},_pending:function(t){if(!t.created_ts)return"";var e=t.started_ts||t.abandoned_ts||new Date;return e<=t.created_ts?"0s":this._timeDiffExact(t.created_ts,e)},_promptClosed:function(t){t.detail.confirmed&&(this._dialog_prompt.startsWith("cancel")?this._cancelTask():this._retryTask())},_promptCancel:function(){this.set("_dialog_prompt","cancel task "+this.task_id),this.$.prompt.open()},_promptRetry:function(){this.set("_dialog_prompt","retry task "+this.task_id),this.$.prompt.open()},_rawOutput:function(t,e){return t?t:"PENDING"===e.state||"RUNNING"===e.state?"[No output yet]":"[No output received]"},_refresh:function(){this.$.data.reload()},_requestUpdated:function(t){this._noMilo(t)&&this.set("_show_raw",1)},_softRefresh:function(){if(!this._result||"RUNNING"===this._result.state||"PENDING"===this._result.state){this.$.data.reload();var t=this.$$("iframe");t&&(t.src=this._getDisplayServerLink(this._server_details.display_server_url_template,this.task_id))}},_retryTask:function(){if(!this._request)return void sk.errorMessage("Task not yet loaded",3e3);var t={expiration_secs:this._request.expiration_secs,name:this._request.name+" (retry)",parent_task_id:this._request.parent_task_id,priority:this._request.priority,properties:this._request.properties,tags:this._request.tags,user:this._profile.email,service_account:this._request.service_account};swarming.postWithToast("/api/swarming/v1/tasks/new","Retrying task "+this.task_id,this._auth_headers,t).then(function(t){t=JSON.parse(t),t&&t.task_id&&this.set("task_id",t.task_id)}.bind(this),function(t){console.log("Task could not be retried",t)})},_rowspan:function(t){return t=t||[],t.length+1},_supportsMilo:function(t,e){return!e&&t&&this._tag(t,"allow_milo")},_toggleDetails:function(){this.set("_request_detail",!this._request_detail)},_tag:function(t,e){if(t&&t.tagMap)return t.tagMap[e]},_wasPickedUp:function(t){return t&&t.state!==this.PENDING&&t.state!==this.CANCELED&&t.state!=this.EXPIRED},_wasNotPickedUp:function(t){return t&&!this._wasPickedUp(t)}})}()</script> </dom-module> </div></body></html>
|
|
|