summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stone <daniels@collabora.com>2016-02-23 14:40:38 (GMT)
committerDaniel Stone <daniels@collabora.com>2016-02-23 14:40:38 (GMT)
commit8e9e4408ec2f362493289b3eddf9f90559a8bdc3 (patch)
treefb0edbd998d222d952fb894ba5ef60ea6bf2dcce
downloadcollabora-ci-tools-8e9e4408ec2f362493289b3eddf9f90559a8bdc3.tar.gz
collabora-ci-tools-8e9e4408ec2f362493289b3eddf9f90559a8bdc3.tar.xz
Initial dump
-rw-r--r--README2
-rwxr-xr-xenergenie-power95
-rwxr-xr-xgit-hook-jenkins105
-rwxr-xr-xhdmi-mux/hdmi-mux133
-rw-r--r--hdmi-mux/hdmi-mux.service11
5 files changed, 346 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..43f2ef3
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+This is a collection of tools used for Collabora's hardware-based CI projects,
+primarily the kernelci.org lab, together with LAVA.
diff --git a/energenie-power b/energenie-power
new file mode 100755
index 0000000..437e10a
--- /dev/null
+++ b/energenie-power
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Uses the web interface to control an Energenie ENER011 power strip.
+#
+# Copyright © 2015 Collabora, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# Author: Daniel Stone <daniels@collabora.com>
+
+set -e
+
+export ENERGENIE_HOST="1.2.3.4"
+export ENERGENIE_PW="1"
+
+curl -s -d pw=$ENERGENIE_PW http://$ENERGENIE_HOST/login.html >/dev/null
+
+if [ "$1" = "status" ]; then
+ STATES=$(curl -s http://$ENERGENIE_HOST/energenie.html | sed -n -e 's/^.*var sockstates = \[\([01,]*\)\].*$/\1/p;')
+ OLD_IFS=$IFS
+ IFS=,
+ i=1
+ for state in $STATES; do
+ case "$state" in
+ 0)
+ nice=off
+ ;;
+ 1)
+ nice=on
+ ;;
+ esac
+ echo "Socket $i: $nice"
+ i=$((i + 1))
+ done
+ IFS=$OLD_IFS
+else
+ case "$1" in
+ big)
+ port=1
+ ;;
+ rpi2)
+ port=2
+ ;;
+ xu3)
+ port=3
+ ;;
+ rock2)
+ port=4
+ ;;
+ 1|2|3|4)
+ port=$1
+ ;;
+ *)
+ echo "which machine??"
+ exit 1
+ ;;
+ esac
+
+ case "$2" in
+ on)
+ curl -s -d cte$port=1 http://$ENERGENIE_HOST >/dev/null
+ ;;
+ off)
+ curl -s -d cte$port=0 http://$ENERGENIE_HOST >/dev/null
+ ;;
+ rb|reboot)
+ curl -s -d cte$port=0 http://$ENERGENIE_HOST >/dev/null
+ sleep 1
+ curl -s -d cte$port=1 http://$ENERGENIE_HOST >/dev/null
+ ;;
+ *)
+ echo "you want to do what??"
+ exit 1
+ ;;
+ esac
+fi
+
+curl -s -d pw= http://$ENERGENIE_HOST/login.html >/dev/null
diff --git a/git-hook-jenkins b/git-hook-jenkins
new file mode 100755
index 0000000..8802185
--- /dev/null
+++ b/git-hook-jenkins
@@ -0,0 +1,105 @@
+#!/usr/bin/python3
+#
+# Takes a git branch update and submits this to Jenkins as a build job. Call
+# from post-receive as:
+#
+# while read oldrev newrev refname; do
+# case "$refname" in
+# refs/ci/*)
+# if ! test "x$newrev" = "x"; then
+# jenkins-kernel-submit "remote-branch-name#${1}"
+# fi
+# ;;
+# *)
+# ;;
+# done
+#
+# Copyright © 2016 Collabora, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# Author: Daniel Stone <daniels@collabora.com>
+
+import os
+import sys
+import time
+
+import jenkins
+
+SERVER_NAME = "https://jenkins.freedesktop.org"
+USER_NAME = "git-bot"
+PASSWORD = ""
+JOB_NAME = "kernel-prepare-build"
+ARGS = ["TREE_BRANCH_LIST", "ARCH_LIST"]
+
+if len(sys.argv) != len(ARGS) + 1:
+ print("Invalid arguments: expected %d arguments, got %d." %
+ (len(ARGS), len(sys.argv)))
+ print("Usage: %s %s" % (sys.argv[0], " ".join(ARGS)))
+ sys.exit(1)
+
+build_args = {}
+for i in range(1, len(sys.argv)):
+ build_args[ARGS[i - 1]] = sys.argv[i]
+
+server = jenkins.Jenkins(SERVER_NAME, username=USER_NAME, password=PASSWORD)
+
+# This is pretty incredible: the submission doesn't return a job number for
+# the job it just created, and in fact you'll get a 404 when you try to query
+# it immediately after. So as there's no race-free way to figure out which
+# job we just kicked off, try to hammer it a bit.
+job_info = server.get_job_info(JOB_NAME)
+predicted_build_number = job_info["nextBuildNumber"]
+server.build_job(JOB_NAME, build_args)
+
+i = 0
+while i < 30:
+ try:
+ build_info = None
+ build_info = server.get_build_info(JOB_NAME, predicted_build_number)
+ except Exception as e:
+ pass
+ if build_info:
+ mispredict = False
+ for param in build_info["actions"][0]["parameters"]:
+ if not param["name"] in build_args or \
+ build_args[param["name"]] != param["value"]:
+ print("Build number %d mispredicted, trying %d ...\n" %
+ (predicted_build_number, predicted_build_number + 1))
+ predicted_build_number += 1
+ mispredict = True
+ print(build_info)
+
+ if not mispredict:
+ break
+
+ i += 1
+ if (i % 10) == 0:
+ print("Still waiting for job to appear on CI ...")
+ time.sleep(1)
+
+if not build_info:
+ print("Submitted to CI, but couldn't find build; expected %d ..." %
+ predicted_build_number)
+ sys.exit(1)
+
+
+print("Submitted to CI: results for %s will be available at %s" %
+ (build_info["displayName"], build_info["url"]))
diff --git a/hdmi-mux/hdmi-mux b/hdmi-mux/hdmi-mux
new file mode 100755
index 0000000..c551fc9
--- /dev/null
+++ b/hdmi-mux/hdmi-mux
@@ -0,0 +1,133 @@
+#!/usr/bin/python3
+#
+# Uses the RS-232 interface to control a Monoprice/SyvioHD 4x4 HDMI mux,
+# switching input and output as appropriate. Getting the current status
+# is untested, as this requires a specially-wired RS-232 cable, with
+# RTS/CTS swapped.
+#
+#
+# Copyright © 2015 Collabora, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# Author: Daniel Stone <daniels@collabora.com>
+
+import argparse
+import os
+import serial
+import socketserver
+import sys
+import time
+
+
+class MuxConnection():
+ def __init__(self, path, inputs, outputs):
+ self.inputs = inputs
+ self.outputs = outputs
+ self.mux = serial.Serial(port=path,
+ baudrate=9600,
+ bytesize=serial.EIGHTBITS,
+ parity=serial.PARITY_NONE,
+ stopbits=serial.STOPBITS_ONE,
+ xonxoff=False,
+ rtscts=False,
+ dsrdtr=True,
+ timeout=5,
+ writeTimeout=5)
+
+ def send(self, msb):
+ send = bytearray((msb, (msb ^ 0xff) & 0xff, 0xd5, 0x7b))
+ for byte in send:
+ self.mux.write(bytes(byte))
+ self.mux.flush()
+ time.sleep(0.03)
+
+ def switch(self, input, output):
+ if not input in self.inputs:
+ raise ValueError("Unknown input %s" % input)
+ if not output in self.outputs:
+ raise ValueError("Unknown output %s" % output)
+
+ byte = self.inputs[input] - 1
+ byte *= 0x04 * (self.outputs[output] - 1)
+ self.send(byte)
+ self.send(0x28) # store configuration
+
+
+class MuxReqHandler(socketserver.BaseRequestHandler):
+ def handle(self):
+ data = self.request.recv(1024).strip()
+ try:
+ decoded = data.decode("utf-8")
+ (input, output) = decoded.split(" ")
+ except Exception as e:
+ out = "Malformed request: %s\n" % data
+ self.request.sendall(out.encode("utf-8"))
+ return
+
+ if input == "power":
+ self.server.mux_conn.send(0x10)
+ out = "Toggled power\n"
+ self.request.sendall(out.encode("utf-8"))
+ return
+
+ try:
+ self.server.mux_conn.switch(input, output)
+ except Exception as e:
+ out = "%s\n" % e
+ self.request.sendall(out.encode("utf-8"))
+ return
+
+ out = "Switched %s to %s\n" % (input, output)
+ self.request.sendall(out.encode("utf-8"))
+
+
+class MuxTCPServer(socketserver.TCPServer):
+ def __init__(self, hostname, port, mux_conn):
+ self.mux_conn = mux_conn
+ socketserver.TCPServer.__init__(self, (hostname, port), MuxReqHandler)
+
+def run_server():
+ parser = argparse.ArgumentParser(description="Handle HDMI mux switch requests")
+ parser.add_argument("--mux-device", required=True,
+ help="Path to serial device")
+ parser.add_argument("--hostname", default="",
+ help="Hostname to listen on (default: any)")
+ parser.add_argument("--port", type=int, default=3199,
+ help="Port to listen on (default: 3199)")
+ args = parser.parse_args()
+
+ # FIXME: Take inputs/outputs as argument, or read config file ...
+ inputs = {
+ "exynos5800-peach-pi-cbg-0": 1,
+ "tegra124-nyan-big-cbg-0": 2,
+ "rk3288-rock2-square-cbg-0": 3,
+ "exynos5422-odroidxu3-cbg-0": 4
+ }
+ outputs = {
+ "chamelium-cbg-0": 1
+ }
+
+ mux_conn = MuxConnection(args.mux_device, inputs, outputs)
+ server = MuxTCPServer(args.hostname, args.port, mux_conn)
+ server.serve_forever()
+
+if __name__ == '__main__':
+ run_server()
diff --git a/hdmi-mux/hdmi-mux.service b/hdmi-mux/hdmi-mux.service
new file mode 100644
index 0000000..03f271b
--- /dev/null
+++ b/hdmi-mux/hdmi-mux.service
@@ -0,0 +1,11 @@
+# FIXME: Parameterise via device name and kick from udev rules (cf. servo),
+# move various bits to configuration as well
+
+[Unit]
+Description="HDMI mux manager"
+ConditionPathExists=/dev/usb-serial/hdmi-mux-cbg-0
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/hdmi-mux --mux-device=/dev/usb-serial/hdmi-mux-cbg-0
+Restart=on-failure