blob: 443e4b6d4d7b7992306589d098c93d1c5ad323d5 [file] [log] [blame]
<!-- The <push-server-sk> custom element declaration.
Displays the server configurations, along with the ability to modify application selections.
Attributes:
servers: Map of server names to the apps and their versions. Such as:
[
{
Name: 'skia-monitoring',
Installed: [
'pull:jcgregorio@jcgregorio.cnc.corp.google.com:2014-12-08T02:09:58Z:79f6b17ea316c5d877f4f1e3fa9c7a4ea950916c.deb',
'logserver/',
]
},
{
Name: 'skia-testing-b',
Installed: []
}
]
Note that an entry in Installed can either be a full package path, or
just a shortened '{appname}/' version which indicates which app is
expected but also signals that no specific release package has been
chosen or deployed yet.
packages: Map of app names to the list of available versions, sorted from newest to oldest. Such as:
{
'pull': [
{
Name: 'pull:jcgregorio@jcgregorio.cnc.corp.google.com:2014-12-08T02:09:58Z:79f6b17ea316c5d877f4f1e3fa9c7a4ea950916c.deb',
Hash: '79f6b17ea316c5d877f4f1e3fa9c7a4ea950916c',
UserID: 'jcgregorio@jcgregorio.cnc.corp.google.com',
Built: '2014-12-08T02:09:58Z',
Dirty: true,
Note: 'some reason for a push'
},
{
Name: 'pull:jcgregorio@jcgregorio.cnc.corp.google.com:2014-12-08T01:39:47Z:323894732847ace1289a9a90192123213.deb',
Hash: '323894732847ace1289a9a90192123213',
UserID: 'jcgregorio@jcgregorio.cnc.corp.google.com',
Built: '2014-12-08T01:39:47Z',
Dirty: false,
Note: 'no reason'
}
],
'logserver': [
]
}
Events:
'change-package'
A 'change-package' event is generated when the user selects a package to push.
The change event has the following attributes:
event.detail.server - The name of the server.
event.detail.name - The full name of the package to push.
Methods:
setConfig(servers, packages)
Clicking on an app brings up a selection dialog with all available options,
the current one already selected. A selection will update and push.
-->
<link rel="import" href="/res/common/imp/confirm-dialog-sk.html">
<dom-module id="push-server-sk">
<style type="text/css" media="screen">
table {
border-spacing: 0;
}
h2 {
color: #33A02C;
margin-left: 1em;
display: inline;
padding-right: 1em;
}
h3 {
margin-left: 1em;
color: #1f78b4;
display: inline;
}
.appName {
padding-right: 1em;
width: 10em;
}
td iron-icon {
padding-right: 1em;
}
paper-button {
color: #1f78b4;
}
paper-button:hover {
background: #eee;
}
.service {
width: 14em;
}
.status,
.uptime {
width: 10em;
}
.uptime {
font-family: monospace;
}
tr:nth-child(2n+1) {
background: #eee;
}
</style>
<template>
<confirm-dialog-sk id="reboot_confirm_dialog"></confirm-dialog-sk>
<div on-tap="editClicked">
<h3>Displaying {{displayedCount}} out of {{servers.length}} servers</h3>
<br/><br/><br/>
<template is="dom-repeat" items="{{servers}}" as=server rendered-item-count="{{displayedCount}}"
filter={{_filterServers(filterText)}}>
<section>
<h2>{{server.Name}}</h2>
<paper-button raised data-action="start"
data-name="reboot.target"
data-server$="[[server.Name]]">Reboot</paper-button>
[<a target=_blank href$="{{monURI(server.Name)}}">mon</a>]
[<a target=_blank href$="{{logsURI(server.Name)}}">logs</a>]
<table>
<template is="dom-repeat" items="{{server.Installed}}" as="installed">
<tr>
<td>
<paper-button class=application
data-server$="{{server.Name}}" data-name$="{{installed}}" data-app$="{{prefixOf(installed)}}"><iron-icon icon="create" title="Edit which package is installed."></iron-icon></paper-button>
</td>
<td><div class=appName>{{prefixOf(installed)}}</div></td>
<td><span class=appName><a href$="https://github.com/google/skia-buildbot/compare/{{fullHash(installed)}}...HEAD">{{short(installed)}}</a></span></td>
<td><iron-icon icon$="{{alarmIfNotLatest(installed)}}" title="Out of date."></iron-icon></td>
<td><iron-icon icon$="{{warnIfDirty(installed)}}" title="Uncommited changes when the package was built."></iron-icon></td>
<td><a href$="{{logsFullURI(server.Name,installed)}}">logs</a></td>
<td>
<table>
<template is="dom-repeat" items="{{servicesOf(installed)}}" as="service">
<tr>
<systemd-unit-status-sk machine="{{server.Name}}" service="{{service}}"></systemd-unit-status-sk>
</tr>
</template>
</table>
</td>
</tr>
</template>
</table>
</section>
</template>
<push-selection-sk id=extChooser></push-selection-sk>
</div>
</template>
</dom-module>
<script>
Polymer({
is: "push-server-sk",
properties: {
servers: {
type: Array,
value: function() { return []; },
},
packages: {
type: Array,
value: function() { return []; },
},
ip: {
type: Object,
value: function() { return {}; },
},
packageLookup: {
type: Object,
value: function() { return {}; },
},
server: {
type: String,
value: '',
},
filterText: {
type: String,
value: '',
},
displayedCount: {
type: Number,
value: 0,
}
},
ready: function() {
// When the push-selection-sk dialog notifies us of a selection
// we fill in some more details and pass that along as another
// CustomEvent.
this.$.extChooser.addEventListener('change-package', function(e) {
var detail = {
name: e.detail.name,
server: this.server
};
this.dispatchEvent(new CustomEvent('change-package', {detail: detail}));
}.bind(this));
},
editClicked: function(e) {
var button = sk.findParent(e.target, "PAPER-BUTTON");
if (button == null || !button.dataset.server) {
return
}
this.server = button.dataset.server;
if (button.dataset.action) {
this.$.reboot_confirm_dialog
.open("Proceed with rebooting " + this.server + "?")
.then(function() {
var detail = {
machine: button.dataset.server,
name: button.dataset.name,
action: button.dataset.action,
};
this.dispatchEvent(new CustomEvent('unit-action', {detail: detail, bubbles: true}));
}.bind(this));
} else {
var id = button.dataset.name;
var app = button.dataset.app;
if (app != "") {
this.$.extChooser.choices = this.packages[app];
this.$.extChooser.choice = id;
this.$.extChooser.toggle();
}
}
},
setConfig: function(servers, packages, ip) {
this.servers = servers;
this.packages = packages;
this.ip = ip;
for (appName in this.packages) {
var that = this;
var latest = true;
this.packages[appName].forEach(function(details) {
that.packageLookup[details.Name] = details;
that.packageLookup[details.Name].Latest = latest;
latest = false;
});
}
},
_filterServers: function(filterText) {
return function(server) {
var findMatchingServers = true;
var filterBy = filterText;
if (filterBy.startsWith('^')) {
findMatchingServers = false;
filterBy = filterBy.substring(1);
}
if (filterBy == "") {
return true;
}
// Try to match the server name prefix.
if (server.Name.indexOf(filterBy) == 0) {
return findMatchingServers;
}
// Now try to match the prefix of all server name tokens.
var tokens = server.Name.split('-');
for (var tokenIndex in tokens) {
if (tokens[tokenIndex].indexOf(filterBy) == 0) {
return findMatchingServers;
}
}
// Now try to match the app name prefix.
for (var installedIndex in server.Installed) {
var installed = server.Installed[installedIndex];
var appName = this.prefixOf(installed);
if (appName.indexOf(filterBy) == 0) {
return findMatchingServers;
}
}
return !findMatchingServers;
}.bind(this);
},
// prefixOf is a helper used in templates that returns all the text
// that appears before the first '/'.
prefixOf: function(s) {
return s.split('/')[0];
},
// fullHash is a utility function used in templates to extract the full git hash
// from a package name.
fullHash: function(s) {
return s.slice(s.length-44, s.length-4)
},
// short is a utility function used in templates to truncate strings.
short: function(s) {
return this.fullHash(s).slice(0, 6);
},
alarmIfNotLatest: function(installed) {
if (!this.packageLookup[installed]) {
return ' '; // Don't return an empty string here, to force the icon to change.
} else {
return this.packageLookup[installed].Latest ? ' ' : 'alarm';
}
},
warnIfDirty: function(installed) {
if (!this.packageLookup[installed]) {
return ' '; // Don't return an empty string here, to force the icon to change.
} else {
return this.packageLookup[installed].Dirty ? 'warning' : ' ';
}
},
servicesOf: function(installed) {
var p = this.packageLookup[installed];
if (!p) {
return [];
}
return p.Services;
},
monURI: function(name) {
return "https://" + name + "-10000-proxy.skia.org";
},
logsURI: function(name) {
return "https://console.cloud.google.com/logs/viewer?project=google.com:skia-buildbots&minLogLevel=200&expandAll=false&resource=logging_log%2Fname%2F" + name;
},
logsFullURI: function(name, installed) {
var app = installed.split('/')[0];
return "https://console.cloud.google.com/logs/viewer?project=google.com:skia-buildbots&minLogLevel=200&expandAll=false&resource=logging_log%2Fname%2F" + name + "&logName=projects%2Fgoogle.com:skia-buildbots%2Flogs%2F" + app;
},
});
</script>