diff --git a/Dockerfile b/Dockerfile index 0167c75..60d8e4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,7 @@ RUN set -xeo pipefail && \ rm "/etc/apk/keys/sgerrand.rsa.pub" && \ rm "/root/.wget-hsts" && \ rm "/tmp/glibc.apk" "/tmp/glibc-bin.apk" && \ + mkdir -p /opt && \ rm -r /var/cache/apk/APKINDEX.* && \ npm install rethinkdb @@ -27,7 +28,7 @@ COPY bin/* / COPY supervisor/supervisord.conf /etc COPY cron/root /var/spool/cron/crontabs/root -RUN chmod +x /bootstrap.sh /clean.js /label.js /root/.android/update-platform-tools.sh && \ +RUN chmod +x /*.sh /clean.js /label.js /root/.android/update-platform-tools.sh && \ /root/.android/update-platform-tools.sh EXPOSE 5037 diff --git a/adb/test-butler-app-1.3.1.apk b/adb/test-butler-app-1.3.1.apk deleted file mode 100644 index c17caba..0000000 Binary files a/adb/test-butler-app-1.3.1.apk and /dev/null differ diff --git a/adb/test-butler-app-2.2.1.apk b/adb/test-butler-app-2.2.1.apk new file mode 100644 index 0000000..105e06e Binary files /dev/null and b/adb/test-butler-app-2.2.1.apk differ diff --git a/bin/adb-reconnect.sh b/bin/adb_reconnect.sh similarity index 63% rename from bin/adb-reconnect.sh rename to bin/adb_reconnect.sh index 3d9b0fc..0aca14e 100644 --- a/bin/adb-reconnect.sh +++ b/bin/adb_reconnect.sh @@ -2,5 +2,5 @@ while read d do - adb -s $d reconnect + timeout -t 3 adb -s $d reconnect done < "${1:-/dev/stdin}" diff --git a/bin/adb_server.sh b/bin/adb_server.sh new file mode 100644 index 0000000..0a28045 --- /dev/null +++ b/bin/adb_server.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +adb -P 5037 kill-server +killall adb || echo ... and it is good +ps ax | grep -i 'stf provider' | grep -v grep | awk '{print $1}' | xargs kill +if [ ! -z "$STF_PROVIDER_PUBLIC_IP" ]; then + /clean.js +fi +adb -a -P 5037 server nodaemon diff --git a/bin/bootstrap.sh b/bin/bootstrap.sh index 55960a6..493821c 100644 --- a/bin/bootstrap.sh +++ b/bin/bootstrap.sh @@ -26,13 +26,13 @@ else } clean() { - node /clean.js + /clean.js exit 0 } bootstrap() { echo "Initiating bootstrap" - timeout -t 20 adb -s $ip install /root/.android/test-butler-app-1.3.1.apk + timeout -t 20 adb -s $ip install /root/.android/test-butler-app-2.2.1.apk } trap clean SIGINT diff --git a/bin/clean.js b/bin/clean.js old mode 100644 new mode 100755 diff --git a/bin/device-status-monitor.js b/bin/device-status-monitor.js new file mode 100644 index 0000000..cd6d2d5 --- /dev/null +++ b/bin/device-status-monitor.js @@ -0,0 +1,80 @@ +#!/usr/bin/node + +var r = require('rethinkdb') +var hostname = process.env.HOSTNAME; +var now = new Date().getTime(); +var fs = require('fs'); + +var status_timeout = { + '3': 24 * 60 * 60 * 1000, // Normal idle devices will be rebooted once per day + '1': 2 * 60 * 1000, // Offline + '2': 2 * 60 * 1000, // Unauthorized + '5': 5 * 60 * 1000 // Connected +} +var present_timeout = 5 * 60 * 1000; +var ready_timeout = 5 * 60 * 1000; +var default_timeout = 4 * 60 * 60 * 1000; + +function calculateTimeout(device) { + if (!device.present) { + return present_timeout; + } else if (!device.ready) { + return ready_timeout; + } else if (device.status in status_timeout) { + return status_timeout[device.status]; + } else { + return default_timeout; + } +} + +function compositeStatus(device) { + return `${device.present}-${device.ready}-${device.status}-${device.owner == null}` +} + +r.connect({ + host: process.env.RETHINKDB_URL, + port: process.env.RETHINKDB_PORT, + db: 'stf', + authKey: process.env.RETHINKDB_ENV_AUTHKEY +}, function(err, conn) { + if (err) throw err; + + + r.table('devices') + .filter({ + provider: { + name: `${hostname}` + } + }) + .run(conn, function(err, cursor) { + if (err) throw err; + + cursor.each(function(err, device) { + var filename = '/tmp/' + device.serial + ".json" + + fs.readFile(filename, 'utf-8', function(err, contents) { + var state = {} + if (!err) { + state = JSON.parse(contents); + } + + var newStatus = compositeStatus(device); + var needUpdate = false; + + if (state.status != newStatus) { + needUpdate = true; //just update + } else if (now - state.time > calculateTimeout(device)) { + console.log(device.serial); + needUpdate = true; // prevent rebooting every minute if something is wrong + } + + if (needUpdate) { + state.time = now; + state.status = newStatus; + fs.writeFileSync(filename, JSON.stringify(state, null, 2) , 'utf-8'); + } + }); + }); + conn.close(); + }); +}); diff --git a/bin/device_setup.sh b/bin/device_setup.sh new file mode 100755 index 0000000..4b2d1b9 --- /dev/null +++ b/bin/device_setup.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +DL=/tmp/devices_list + +rm -f $DL +touch -f $DL +sleep 10 + +cd / || exit + +function clean_agoda_staff { + local DEVICE=$1 + + echo -n | timeout -t 30 adb -s "${DEVICE}" shell rm -rf /sdcard/fork /sdcard/marathon /sdcard/screenshotEspressoTesting +} + +function setup_emulator { + local DEVICE=${1} + local MARATHON_SERIAL + MARATHON_SERIAL=$(timeout -t 30 adb -s "${DEVICE}" shell getprop marathon.serialno | tr -d '\r') + + if [ -z "${MARATHON_SERIAL}" ]; then + local SERIAL + SERIAL=$(hostname) + timeout -t 30 bash -c 'until timeout -t 30 adb -s '"${DEVICE}"' shell service list | grep -qE -- "package|settings"; do sleep 1; done' + timeout -t 30 adb -s "${DEVICE}" shell su root setprop marathon.serialno "${SERIAL}" + timeout -t 30 adb -s "${DEVICE}" shell su root pm disable org.chromium.webview_shell + timeout -t 30 adb -s "${DEVICE}" shell su root settings put secure spell_checker_enabled 0 + timeout -t 30 adb -s "${DEVICE}" shell su root settings put secure immersive_mode_confirmations confirmed + timeout -t 30 adb -s "${DEVICE}" shell su root settings put global window_animation_scale 0 + timeout -t 30 adb -s "${DEVICE}" shell su root settings put global transition_animation_scale 0 + timeout -t 30 adb -s "${DEVICE}" shell su root settings put global animator_duration_scale 0 + if [ -n "${EMULATOR_TIMEZONE}" ]; then + timeout -t 30 adb -s "${DEVICE}" shell su root setprop persist.sys.timezone "${EMULATOR_TIMEZONE}" + fi + if [ -n "${HTTP_PROXY}" ]; then + timeout -t 30 adb -s "${DEVICE}" shell settings put global http_proxy "${HTTP_PROXY}" + fi + timeout -t 30 adb -s "${DEVICE}" shell su root 'echo "chrome --disable-fre --no-default-browser-check --no-first-run" > /data/local/tmp/chrome-command-line' + fi +} + +while sleep 1; do + echo -n | adb devices | grep -E 'device$' | awk '{ print $1 }' | sort >$DL.new + diff -u $DL $DL.new | grep '^[+][^+]' | sed -E 's/^\+//' | while read -r d; do + + echo Connected "${d}" + + clean_agoda_staff "${d}" + done + + if [ -n "${STF_PROVIDER_PUBLIC_IP}" ]; then + for d in $(cat $DL.new); do + # Emulator + setup_emulator "${d}" + done + fi + + mv "${DL}.new" "${DL}" +done diff --git a/bin/get-local-offline.js b/bin/get-local-offline.js deleted file mode 100644 index 26e8ec4..0000000 --- a/bin/get-local-offline.js +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/node - -var r = require('rethinkdb') -var hostname = process.env.HOSTNAME; - -r.connect({ - host: process.env.RETHINKDB_URL, - port: process.env.RETHINKDB_PORT, - db: 'stf', - authKey: process.env.RETHINKDB_ENV_AUTHKEY -}, function(err, conn) { - if (err) throw err; - - r.table('devices') - .filter({ - provider: { - name: `${hostname}` - }, - status: 1 - }) - .withFields('serial') - .run(conn, function(err, cursor) { - if (err) throw err; - - cursor.each(function(err, serial) { - console.log(serial.serial); - }) - conn.close(); - }); -}); diff --git a/bin/get-local-unauthorized.js b/bin/get-local-unauthorized.js deleted file mode 100644 index 0b76776..0000000 --- a/bin/get-local-unauthorized.js +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/node - -var r = require('rethinkdb') -var hostname = process.env.HOSTNAME; - -r.connect({ - host: process.env.RETHINKDB_URL, - port: process.env.RETHINKDB_PORT, - db: 'stf', - authKey: process.env.RETHINKDB_ENV_AUTHKEY -}, function(err, conn) { - if (err) throw err; - - r.table('devices') - .filter({ - provider: { - name: `${hostname}` - }, - status: 2 - }) - .withFields('serial') - .run(conn, function(err, cursor) { - if (err) throw err; - - cursor.each(function(err, serial) { - console.log(serial.serial); - }) - conn.close(); - }); -}); diff --git a/bin/metrics-battery.js b/bin/metrics-battery.js deleted file mode 100644 index d9471dc..0000000 --- a/bin/metrics-battery.js +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/node - -var r = require('rethinkdb') -var fs = require('fs'); -var hostname = process.env.HOSTNAME; - -r.connect({ - host: process.env.RETHINKDB_URL, - port: process.env.RETHINKDB_PORT, - db: 'stf', - authKey: process.env.RETHINKDB_ENV_AUTHKEY -}, function(err, conn) { - if (err) throw err; - - r.table('devices') - .filter({ - provider: { - name: `${hostname}` - }, - status: 3, - present: true - }) - .withFields('serial', 'battery', 'provider') - .run(conn, function(err, cursor) { - if (err) throw err; - - var stream = fs.createWriteStream("/custom-metrics/battery"); - stream.once('open', function(fd) { - cursor.each(function(err, device) { - stream.write(`android_battery,serial=\"${device.serial}\" voltage=${device.battery.voltage},level=${device.battery.level}i,temperature=${device.battery.temp} ${Date.now()}\n`); - }, function() { - stream.end(); - }) - }); - stream.once('finish', function(){ - conn.close(); - }); - }); -}); diff --git a/bin/metrics.sh b/bin/metrics.sh index 492f113..6edbbb6 100644 --- a/bin/metrics.sh +++ b/bin/metrics.sh @@ -1,3 +1,3 @@ -#/usr/bin/env bash +#!/usr/bin/env bash adb devices | sed -n '1!p' | sed '$d' | awk '{gsub("device","online",$2); print "android,serial="$1",status="$2"","value=1",systime()}' > /custom-metrics/devices diff --git a/bin/usb-rebind.sh b/bin/usb-rebind.sh index 41cae68..89a7406 100644 --- a/bin/usb-rebind.sh +++ b/bin/usb-rebind.sh @@ -1,4 +1,4 @@ -#/usr/bin/env bash +#!/usr/bin/env bash # set -x diff --git a/cron/root b/cron/root index 09ed60c..0418472 100644 --- a/cron/root +++ b/cron/root @@ -1,6 +1,4 @@ * * * * * /bin/bash /metrics.sh * * * * * /bin/bash /usb-rebind.sh * * * * * /usr/bin/node /label.js -* * * * * /usr/bin/node /metrics-battery.js -* * * * * /usr/bin/node /get-local-offline.js | /bin/bash /adb-reconnect.sh -* * * * * /usr/bin/node /get-local-unauthorized.js | /bin/bash /adb-reconnect.sh +* * * * * /usr/bin/node /device-status-monitor.js | /bin/bash /adb_reconnect.sh diff --git a/supervisor/supervisord.conf b/supervisor/supervisord.conf index 33a0db9..279f3db 100644 --- a/supervisor/supervisord.conf +++ b/supervisor/supervisord.conf @@ -19,15 +19,38 @@ serverurl = unix:///tmp/supervisor.sock [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface -[program:adb] -command=/bin/bash -c "adb -P 5037 kill-server; adb -a -P 5037 server nodaemon" -autorestart=true +# [program:adb] +# command=/adb_server.sh +# autorestart=true +# priority=10000 +# stdout_logfile = /tmp/adb_server.log +# stdout_logfile_maxbytes = 50MB +# stderr_logfile = /tmp/adb_server_err.log +# stderr_logfile_maxbytes = 50MB [program:bootstrap] -command=/bin/bash /bootstrap.sh +command=/bootstrap.sh +priority=8000 +stdout_logfile = /tmp/bootstrap.log +stdout_logfile_maxbytes = 50MB +stderr_logfile = /tmp/bootstrap_err.log +stderr_logfile_maxbytes = 50MB + +[program:device_setup] +command=/device_setup.sh +autorestart=true +priority=7000 +stdout_logfile = /tmp/device_setup.log +stdout_logfile_maxbytes = 50MB +stderr_logfile = /tmp/device_setup_err.log +stderr_logfile_maxbytes = 50MB [program:cron] command=crond -f +stdout_logfile = /tmp/cron.log +stdout_logfile_maxbytes = 50MB +stderr_logfile = /tmp/cron_err.log +stderr_logfile_maxbytes = 50MB [include] files = /etc/supervisord.d/*.conf