Updating maintenance scripts.

Updating some scripts we use to maintain AV ANalysis
recording servers.

BUG=None
TEST=Tested Locally
Exempt-From-Owner-Approval:Had to blow away repo and
download changes from gerrit. Somehow, it now thinks
CheckAVDevices.py is owned by aashutoshk, which is
incorrect.

Change-Id: If6e03cfd907a0ab1040de272e0305e1641ca3855
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crostestutils/+/1832900
Commit-Queue: Vinayak Suley <vsuley@chromium.org>
Tested-by: Vinayak Suley <vsuley@chromium.org>
Auto-Submit: Vinayak Suley <vsuley@chromium.org>
Reviewed-by: Vinayak Suley <vsuley@chromium.org>
diff --git a/provingground/av_analysis/CheckAVDevices.py b/provingground/av_analysis/CheckAVDevices.py
new file mode 100755
index 0000000..d389a56
--- /dev/null
+++ b/provingground/av_analysis/CheckAVDevices.py
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+
+from __future__ import unicode_literals
+import json
+import os
+import sys
+import subprocess
+
+from time import time
+from prompt_toolkit import PromptSession
+from prompt_toolkit.completion import WordCompleter
+
+from common.cmd_helper import *
+from common.av_helper import *
+
+# Globals
+_menu_items = [
+    'ping_recorders',
+    'prep_host_for_ssh',
+    'ssh_to_rec',
+    'update_full_server'
+    'update_servlet',
+    'create_test_recording',
+    'get_recorder_status',
+]
+_cros = '.cros'
+_recorder = '-recorder'
+_FNULL = open(os.devnull, 'w')
+
+
+def load_active_duts():
+    with open('all_duts.json') as file:
+        data = json.load(file)
+        return data['active']
+
+
+def main(argv):
+
+    session = PromptSession()
+    menu_completer = WordCompleter(_menu_items, ignore_case=True)
+
+    while True:
+        try:
+            choice = session.prompt('Main Menu > ', completer=menu_completer)
+            choice = choice.lower()
+        except KeyboardInterrupt:
+            continue
+        except EOFError:
+            break
+        else:
+            for host in load_active_duts():
+                # globals()[choice]() lets us call the appropriate method
+                # with str value instead of hard identifier.
+                globals()[choice](host)
+    print('GoodBye!')
+
+
+def print_help():
+    print('Type in one of the following options into the prompt:')
+    for item in _menu_items:
+        print(' - ' + item)
+    print('Or hit Ctrl + D to exit.')
+
+
+def ping_recorders(host):
+    rec_name = host + _recorder + _cros
+    rec_ping_args = ['ping', '-c', '1', rec_name]
+    response = subprocess.call(rec_ping_args, stdout=_FNULL)
+    print "REC: {0:50} Ping Result: {1}".format(rec_name, response)
+
+
+def update_servlet(host):
+    rec_name = host + _recorder + _cros
+    filename = 'servlet.py'
+    src_filepath = os.path.join(os.getcwd(), 'recording_server', filename)
+    dst_filepath = os.path.join('~', 'servlet', filename)
+    scp_destination = 'root@{0}:{1}'.format(rec_name, dst_filepath)
+
+    scp_args = ['scp',
+                src_filepath,
+                scp_destination]
+    subprocess.call(scp_args, stdout=subprocess.PIPE,
+                    stderr=subprocess.PIPE)
+
+
+def update_full_server(host):
+    rec_name = host + _recorder + _cros
+    ssh_destination = 'root@{0}'.format(rec_name)
+    src_filepath = os.path.join(os.getcwd(), 'recording_server')
+    dst_filepath = os.path.join('~', 'recording_server')
+    scp_destination = '{0}:{1}'.format(ssh_destination, dst_filepath)
+
+    del_args = ['ssh',
+                ssh_destination,
+                "rm -r recording_server"]
+    subprocess.call(del_args)
+
+    scp_args = ['scp',
+                '-r',
+                src_filepath,
+                scp_destination]
+    subprocess.call(scp_args)
+
+
+def ssh_to_rec(host):
+    rec_name = host + _recorder + _cros
+    ssh_destination = 'root@' + rec_name
+    ssh_args = 'gnome-terminal --tab -- ssh ' + ssh_destination
+    subprocess.call(ssh_args, shell=True)
+
+
+def create_test_recording(host):
+    rec_name = host + _recorder + _cros
+
+    # Hygiene
+    video_device = get_vid_device()
+    cmd = 'lsof -t {0}'.format(video_device)
+    proc = None
+    proc = run_remotely(cmd=cmd,
+                        host=rec_name,
+                        title='Checkig Video Device',
+                        print_output=False,
+                        process_error_okay=True)
+    if proc is not None:
+        kill_cmd = 'kill -9 {0}'.format(proc)
+        run_remotely(cmd=kill_cmd,
+                     host=rec_name,
+                     title='Killing proc using video device.',
+                     print_output=False,
+                     process_error_okay=False)
+    run_remotely(cmd=get_module_remove_cmd(), host=rec_name,
+                 title='Remove Modules', print_output=True,
+                 process_error_okay=False)
+    run_remotely(cmd=get_module_add_cmd(), host=rec_name,
+                 title='Add Modules', print_output=True,
+                 process_error_okay=False)
+
+    # Audio recording.
+    audio_file = 'audio_test_{0}.wav'.format(str(int(time())))
+    audio_cmd = 'ffmpeg -f alsa -i hw:1 -t 10 {0}'.format(audio_file)
+    run_remotely(cmd=audio_cmd, host=rec_name,
+                 title='AUDIO RECORDING', print_output=True,
+                 process_error_okay=False)
+    copy_from_remote(host=rec_name,
+                     source_name=audio_file,
+                     destination_name=audio_file)
+
+    # Video recording.
+    video_file = 'video_test_{0}.mp4'.format(str(int(time())))
+    video_cmd = 'ffmpeg -f video4linux2 -s 1920x1080 -r 60 -i '\
+                '/dev/video0 -f alsa -i hw:1 -qscale 2 -t 10 '\
+                '-strict experimental -acodec aac -vcodec libx264 '\
+                '-pix_fmt yuv420p -loglevel debug -y {0}'\
+                .format(video_file)
+    run_remotely(cmd=video_cmd, host=rec_name,
+                 title='VIDEO RECORDING', print_output=True,
+                 process_error_okay=False)
+    copy_from_remote(host=rec_name,
+                     source_name=video_file,
+                     destination_name=video_file)
+
+
+def get_recorder_status(host):
+    rec_name = host + _recorder + _cros
+
+    os_ver_cmd = 'hostnamectl'
+    run_remotely(cmd=os_ver_cmd, host=rec_name,
+                 title='OS VERSION', print_output=True,
+                 process_error_okay=False)
+
+    run_remotely(cmd=get_path_command(), host=rec_name,
+                 title='PATH', print_output=True,
+                 process_error_okay=False)
+
+    run_remotely(cmd=get_ffmpeg_ver_cmd(), host=rec_name,
+                 title='FFMPEG VERSION', print_output=True,
+                 process_error_okay=False)
+
+    run_remotely(cmd=get_video_devices_cmd(), host=rec_name,
+                 title='VIDEO DEVICES', print_output=True,
+                 process_error_okay=False)
+
+    run_remotely(cmd=get_audio_devices_cmd(), host=rec_name,
+                 title='AUDIO DEVICES', print_output=True,
+                 process_error_okay=False)
+
+
+def prep_host_for_ssh(host):
+    rec_name = host + _recorder + _cros
+    ssh_destination = 'root@' + rec_name
+    cmd_args = 'gnome-terminal --tab -- ssh-copy-id -i ~/.ssh/id_rsa.pub ' + \
+               ssh_destination
+    subprocess.call(cmd_args, shell=True)
+
+
+def get_ssh_args(device_name):
+    ssh_args = ['ssh',
+                'root@{0}'.format(device_name)]
+    return ssh_args
+
+
+def execute_command(args_list, title=None, new_tab=False):
+    if title is not None:
+        print('\n\n{0}:\n'.format(title))
+    try:
+        subprocess.check_output(args_list)
+    except subprocess.CalledProcessError:
+        print('Caught CalledProcessError. \n')
+
+
+if __name__ == '__main__':
+    main(sys.argv)
+
+'''
+Things that I still need to figure out:
+- How to check if ffmpeg is installed on the system.
+- How to check if the serverlet is running on the system.
+'''
diff --git a/provingground/av_analysis/all_duts.json b/provingground/av_analysis/all_duts.json
new file mode 100644
index 0000000..916b064
--- /dev/null
+++ b/provingground/av_analysis/all_duts.json
@@ -0,0 +1,32 @@
+{
+	"active":[
+        "chromeos15-row14a-rack5-host2"
+	],
+
+	"all":[
+		"chromeos15-row14a-rack4-host1",
+        "chromeos15-row14a-rack4-host2",
+        "chromeos15-row14a-rack4-host3",
+        "chromeos15-row14a-rack4-host4",
+        "chromeos15-row14a-rack4-host5",
+        "chromeos15-row14a-rack4-host6",
+        "chromeos15-row14a-rack4-host7",
+        "chromeos15-row14a-rack4-host8",
+        "chromeos15-row14a-rack5-host1",
+        "chromeos15-row14a-rack5-host2",
+        "chromeos15-row14a-rack5-host3",
+        "chromeos15-row14a-rack5-host4",
+        "chromeos15-row14a-rack5-host5",
+        "chromeos15-row14a-rack5-host6",
+        "chromeos15-row14a-rack5-host7",
+        "chromeos15-row14a-rack5-host8",
+        "chromeos15-row14b-rack5-host1",
+        "chromeos15-row14b-rack5-host2",
+        "chromeos15-row14b-rack5-host3",
+        "chromeos15-row14b-rack5-host4",
+        "chromeos15-row14b-rack5-host5",
+        "chromeos15-row14b-rack5-host6",
+        "chromeos15-row14b-rack5-host7",
+        "chromeos15-row14b-rack5-host8"
+    ]
+}
\ No newline at end of file
diff --git a/provingground/av_analysis/recording_server/servlet.py b/provingground/av_analysis/recording_server/servlet.py
index 10f95dc..e0f812f 100644
--- a/provingground/av_analysis/recording_server/servlet.py
+++ b/provingground/av_analysis/recording_server/servlet.py
@@ -1,7 +1,7 @@
 import os
 import subprocess
 
-from flask import Flask, request, jsonify
+from flask import Flask, request, jsonify, abort
 import google.cloud
 from google.cloud import storage
 
@@ -10,6 +10,28 @@
 
 def record(filename, duration):
     """Record screen to |filename| and return error message if ffmpeg fails."""
+    video_device = '/dev/video0'
+
+    # Check if the video device exists.
+    cmd = 'ls {0}'.format(video_device)
+    proc = None
+    try:
+        proc = subprocess.check_output(cmd.split())
+    except subprocess.CalledProcessError:
+        abort(500, 'Seems like the video device was not found.')
+
+    # Check if the video device is already in use and kill if so.
+    cmd = 'lsof -t {0}'.format(video_device)
+    proc = None
+    try:
+        proc = subprocess.check_output(cmd.split())
+    except subprocess.CalledProcessError:
+        abort(500, 'No process must\'ve been found. That\'s okay.')
+    if proc is not None:
+        kill_cmd = 'kill -9 {0}'.format(proc)
+        proc = subprocess.call(kill_cmd.split())
+
+    # Reset some modules for safety:
     # TODO(vsuley): This is hacky: fix the underlying problem.
     # crbug.com/970936
     r1 = subprocess.call(['modprobe', '-vr', 'uvcvideo'])
@@ -66,6 +88,13 @@
     return jsonify(status)
 
 
+@app.errorhandler(500)
+def log_and_abort(message):
+    """Logs the error message and also return message"""
+    app.logger.error(message)
+    return message
+
+
 @app.route('/record_and_upload', methods=['POST'])
 def record_and_upload():
     """
@@ -77,8 +106,11 @@
     @returns: JSON containing error status.
 
     """
+    app.logger.info('Args receieved: ' + str(request.args))
     filename = request.args.get('filename')
     duration = request.args.get('duration')
+    post_data = str(request.data.decode('utf-8'))
+    app.logger.info('The form data is: ' + str(post_data))
     status = {}
 
     if not filename or not duration:
@@ -86,11 +118,11 @@
         return jsonify(status), 400
 
     app.logger.info('Starting recording')
-    status['error'] = record(filename, duration)
+    rec_error = record(filename, duration)
 
     # Short circuit if ffmpeg failed.
-    if status.get('error'):
-        return outcome(status, filename)
+    if rec_error is not None:
+        abort(500, rec_error)
 
     app.logger.info('Starting upload')
     status['error'] = upload(filename)