Skip to content

Commit

Permalink
Add basic power-controller web UI
Browse files Browse the repository at this point in the history
This adds a lot of boilerplate too, including a very basic web server.

Bug: skia:
Change-Id: I6743269f2ee23947afea63dfb677f20adece66ba
Reviewed-on: https://skia-review.googlesource.com/17106
Reviewed-by: Stephan Altmueller <[email protected]>
Commit-Queue: Kevin Lubick <[email protected]>
  • Loading branch information
kjlubick authored and Skia Commit-Bot committed May 19, 2017
1 parent f46f96a commit f12cdd6
Show file tree
Hide file tree
Showing 14 changed files with 541 additions and 0 deletions.
3 changes: 3 additions & 0 deletions power/.bowerrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"directory": "third_party/bower_components"
}
2 changes: 2 additions & 0 deletions power/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
res/imp/res
res/res
19 changes: 19 additions & 0 deletions power/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#Use Vulcanize 1.0
VULCANIZE1=true
# The list of files we want to go into core.js, which is concat'd and
# minified. These files should be either present in the project, brought
# into third_party/bower_compoents via bower, or in node_modules.
CORE_SOURCE_FILES = third_party/bower_components/webcomponentsjs/webcomponents.min.js \
../res/js/common.js

BOWER_DIR=third_party/bower_components

default: all

all: clean_webtools core_js elements_html skiaversion power_controller

power_controller:
go install -v ./go/power-controller

include ../webtools/webtools.mk
include ../go/skiaversion/skiaversion.mk
7 changes: 7 additions & 0 deletions power/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Powercycle Controller
=====================

The purpose of this module is to expose a web UI for powercycling various machines in
the Skia fleet.

https://docs.google.com/document/d/15sb7RN_S3ctw06xQoNG7c3Owu-DS2jPPDaWAdQIkPLw/edit#
22 changes: 22 additions & 0 deletions power/bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "power-controller",
"version": "0.0.0",
"authors": [],
"license": "BSD",
"private": true,
"description": "UI for controlling power cycling",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"third_party/bower_components",
"test",
"tests"
],
"dependencies": {
"polymer": "Polymer/polymer#^1.1.0",
"iron-elements": "PolymerElements/iron-elements#^1.0.0",
"iron-flex-layout": "PolymerElements/iron-flex-layout#^1.3.0",
"paper-elements": "PolymerElements/paper-elements#^1.0.0"
}
}
15 changes: 15 additions & 0 deletions power/elements.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<!--
The full set of web components needs for the power-controller UI.
This file will be vulcanized into res/imp/elements.html which is
imported via the templates/header.html file.
-->
<link rel="import" href="/res/imp/bower_components/polymer/polymer.html">

<!-- List all the top level elements here-->
<link rel="import" href="/res/imp/power-index.html" />

</head>
87 changes: 87 additions & 0 deletions power/go/power-controller/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package main

import (
"flag"
"html/template"
"net/http"
"path/filepath"

"github.com/gorilla/mux"

"go.skia.org/infra/go/common"
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/login"
"go.skia.org/infra/go/sklog"
)

const (
// OAUTH2_CALLBACK_PATH is callback endpoint used for the Oauth2 flow.
OAUTH2_CALLBACK_PATH = "/oauth2callback/"
)

var (
// indexTemplate is the main index.html page we serve.
indexTemplate *template.Template = nil
)

var (
// web server params
host = flag.String("host", "localhost", "HTTP service host")
port = flag.String("port", ":8001", "HTTP service port (e.g., ':8002')")
local = flag.Bool("local", false, "Running locally if true. As opposed to in production.")
resourcesDir = flag.String("resources_dir", "", "The directory to find templates, JS, and CSS files. If blank the current directory will be used.")
promPort = flag.String("prom_port", ":20000", "Metrics service address (e.g., ':10110')")
)

func main() {
defer common.LogPanic()
// Calls flag.Parse()
common.InitWithMust(
"power-controller",
common.PrometheusOpt(promPort),
//common.CloudLoggingOpt(),
)

loadTemplates()

runServer()
}

func loadTemplates() {
indexTemplate = template.Must(template.ParseFiles(
filepath.Join(*resourcesDir, "templates/index.html"),
filepath.Join(*resourcesDir, "templates/header.html"),
))
}

// indexHandler displays the index page, which has no real templating. The client side JS will
// query for more information.
func indexHandler(w http.ResponseWriter, r *http.Request) {
if *local {
loadTemplates()
}
w.Header().Set("Content-Type", "text/html")

if err := indexTemplate.Execute(w, nil); err != nil {
sklog.Errorf("Failed to expand template: %v", err)
}
}

func runServer() {
serverURL := "https://" + *host
if *local {
serverURL = "http://" + *host + *port
}

r := mux.NewRouter()
r.PathPrefix("/res/").HandlerFunc(httputils.MakeResourceHandler(*resourcesDir))

r.HandleFunc(OAUTH2_CALLBACK_PATH, login.OAuth2CallbackHandler)
r.HandleFunc("/", indexHandler)

rootHandler := httputils.LoggingGzipRequestResponse(r)

http.Handle("/", rootHandler)
sklog.Infof("Ready to serve on %s", serverURL)
sklog.Fatal(http.ListenAndServe(*port, nil))
}
21 changes: 21 additions & 0 deletions power/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "power-controller",
"version": "0.0.1",
"description": "",
"main": "index.js",
"devDependencies": {
"autoprefixer": "~4.0.0",
"bower": "^1.3.12",
"cssmin": "~0.4.2",
"html-minifier": "~3.0.0",
"http-server": "~0.9.0",
"sinon": "^2.2.0",
"uglify-js": "^2.4.15",
"vulcanize": "~1.10.4"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
9 changes: 9 additions & 0 deletions power/res/imp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Set up the local directory to run the demo pages.
default:
ln -sf ../../res res
ln -sf ../../node_modules node_modules
npm install http-server

# Run a local HTTP server for the demo pages.
run:
../../node_modules/.bin/http-server -p 8080 -a 127.0.0.1
77 changes: 77 additions & 0 deletions power/res/imp/power-index-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<title>power-controller Demo</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">

<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/res/common/js/common.js"></script>
<script src="/res/js/power-controller.js"></script>

<script src="/node_modules/sinon/pkg/sinon-2.2.0.js"></script>

<script type="text/javascript" charset="utf-8">

var server = sinon.fakeServer.create({
// logger: function(msg){console.log(msg)},
});
server.autoRespond = true;

var login = {"Email":"[email protected]","LoginURL":"http://www.example.com","IsAGoogler":true};
server.respondWith("GET","/loginstatus/", JSON.stringify(login));

var version = {"commit":"singedpotato","date":"2017-03-11T16:57:18-05:00"};
server.respondWith("GET","/json/version", JSON.stringify(version));

var data = {
list: [
{
bot_id: "skia-rpi-039",
dimensions: [{"value": ["1"], "key": "android_devices"}, {"value": ["N", "NMF26Q"], "key": "device_os"}, {"value": ["sailfish"], "key": "device_type"}, {"value": ["skia-rpi-046"], "key": "id"}, {"value": ["Android"], "key": "os"}, {"value": ["Skia"], "key": "pool"}, {"value": ["Device Missing"], "key": "quarantined"}],
status: "Device Missing",
since: new Date(new Date().getTime() - 16*60*1000),
silenced: false,
bug_url: "",
},
{
bot_id: "skia-rpi-002",
dimensions: [{"value": ["1"], "key": "android_devices"}, {"value": ["N", "NMF26Q"], "key": "device_os"}, {"value": ["dragon"], "key": "device_type"}, {"value": ["skia-rpi-002"], "key": "id"}, {"value": ["Android"], "key": "os"}, {"value": ["Skia"], "key": "pool"}],
status: "Host Missing",
since: new Date(new Date().getTime() - 25*60*1000),
silenced: false,
bug_url: "",
},
{
bot_id: "skia-e-win-032",
dimensions: [{"value": ["4"], "key": "cores"}, {"value": ["x86", "x86-64"], "key": "cpu"}, {"value": ["8086", "8086:1926"], "key": "gpu"}, {"value": ["skia-e-win-032"], "key": "id"}, {"value": ["n1-standard-4"], "key": "machine_type"}, {"value": ["Windows", "Windows-10", "Windows-10-14393"], "key": "os"}, {"value": ["Skia"], "key": "pool"}],
status: "Host Missing",
since: new Date(new Date().getTime() - 68*60*1000),
silenced: true,
bug_url: "",
},
{
bot_id: "build20-m3",
dimensions: [{"value": ["4"], "key": "cores"}, {"value": ["x86", "x86-64"], "key": "cpu"}, {"value": ["8086", "8086:0a2e"], "key": "gpu"}, {"value": ["0"], "key": "hidpi"}, {"value": ["build20-m3"], "key": "id"}, {"value": ["n1-standard-4"], "key": "machine_type"}, {"value": ["Mac", "Mac-10.11"], "key": "os"}, {"value": ["Skia"], "key": "pool"}, {"value": ["7.0"], "key": "xcode_version"}],
status: "Host Missing",
since: new Date(new Date().getTime() - 250*60*1000),
silenced: true,
bug_url: "https://bugs.chromium.org/p/chromium/issues/entry?summary=[Device%20Restart]%20for%20${id}&description=Please%20Reboot%20${id}&components=Infra%3ELabs&labels=Pri-2,Infra-Troopers,Restrict-View-Google",
}
],
};

server.respondWith("GET", /^\/down_bots/, JSON.stringify(data));


</script>

<link rel="import" href="power-index.html">
</head>
<body>

<power-index></power-index>

</body>
</html>
Loading

0 comments on commit f12cdd6

Please sign in to comment.