Rohan Patel | f49bd1e | 2019-09-23 15:04:19 -0400 | [diff] [blame^] | 1 | # Copyright (c) 2019 AT&T Intellectual Property. #
|
| 2 | # #
|
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); #
|
| 4 | # you may not use this file except in compliance with the License. #
|
| 5 | # You may obtain a copy of the License at #
|
| 6 | # #
|
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 #
|
| 8 | # #
|
| 9 | # Unless required by applicable law or agreed to in writing, software #
|
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, #
|
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
| 12 | # See the License for the specific language governing permissions and #
|
| 13 | # limitations under the License. #
|
| 14 | ################################################################################
|
| 15 |
|
| 16 |
|
| 17 | from flask import Flask, request, make_response, jsonify, g
|
| 18 | import json
|
| 19 | import paramiko
|
| 20 | import datetime
|
| 21 | import logging
|
| 22 | import os
|
| 23 | from logging import FileHandler
|
| 24 |
|
| 25 | # redirect http to https
|
| 26 | app = Flask(__name__)
|
| 27 |
|
| 28 |
|
| 29 | # Prevents print statement every time an endpoint is triggered.
|
| 30 | logging.getLogger("werkzeug").setLevel(logging.WARNING)
|
| 31 |
|
| 32 |
|
| 33 | def unix_time_millis(dt):
|
| 34 | epoch = datetime.datetime.utcfromtimestamp(0)
|
| 35 | return (dt - epoch).total_seconds() * 1000.0
|
| 36 |
|
| 37 |
|
| 38 | @app.route("/otf/vth/ssh/v1/health", methods = ['GET'])
|
| 39 | def getHealth():
|
| 40 | return "UP"
|
| 41 |
|
| 42 |
|
| 43 | @app.route('/otf/vth/ssh/v1', methods = ['POST'])
|
| 44 | def remoteSSH():
|
| 45 | responseData = {
|
| 46 | "vthResponse": {
|
| 47 | "testDurationMS": "",
|
| 48 | "dateTimeUTC": "",
|
| 49 | "abstractMessage": "",
|
| 50 | "resultData": {}
|
| 51 | }
|
| 52 | }
|
| 53 |
|
| 54 | responseData['vthResponse']['dateTimeUTC'] = str(datetime.datetime.now())
|
| 55 | start_time = unix_time_millis(datetime.datetime.now())
|
| 56 |
|
| 57 | try:
|
| 58 | if not request.is_json:
|
| 59 | raise ValueError('Request must be a valid JSON object.')
|
| 60 |
|
| 61 | request_data = request.get_json()
|
| 62 |
|
| 63 | if 'vthInput' in request_data:
|
| 64 | vth_input = request_data['vthInput']
|
| 65 | expected_keys = ['vthName', 'testConfig', 'testData']
|
| 66 | received_keys = vth_input.keys();
|
| 67 | test_data = ""
|
| 68 | test_config = ""
|
| 69 |
|
| 70 | if sorted(expected_keys) == sorted(received_keys):
|
| 71 | test_data = vth_input['testData']
|
| 72 |
|
| 73 | if 'command' not in test_data:
|
| 74 | raise ValueError('Must supply value testData.command')
|
| 75 |
|
| 76 | else:
|
| 77 | raise ValueError('Missing one or more expected keys: {expectedKeys}.'.format(expectedKeys=expected_keys))
|
| 78 |
|
| 79 | test_config = vth_input['testConfig']
|
| 80 |
|
| 81 | if 'jumpServer' not in test_config:
|
| 82 | raise KeyError('Cannot use jump server when jumpServer key is missing.')
|
| 83 |
|
| 84 | jump_server = test_config['jumpServer']
|
| 85 |
|
| 86 | if 'host' not in test_config['jumpServer']:
|
| 87 | raise KeyError('Missing host value in jumpServer.')
|
| 88 |
|
| 89 | host = test_config['jumpServer']['host']
|
| 90 |
|
| 91 | if 'credentials' not in jump_server:
|
| 92 | raise KeyError('Missing credentials in jumpServer.')
|
| 93 |
|
| 94 | credentials = jump_server['credentials']
|
| 95 |
|
| 96 | if 'username' not in credentials:
|
| 97 | raise KeyError('Missing username in credentials.')
|
| 98 |
|
| 99 | username = credentials['username']
|
| 100 |
|
| 101 | if 'password' not in credentials:
|
| 102 | raise KeyError('Missing password in credentials.')
|
| 103 |
|
| 104 | password = credentials['password']
|
| 105 |
|
| 106 | ssh = paramiko.SSHClient()
|
| 107 | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
| 108 |
|
| 109 | if 'usePrivateKey' in test_config:
|
| 110 | if test_config['usePrivateKey']:
|
| 111 | key_passphrase = os.environ.get('id_otf_key_passphrase')
|
| 112 | app.logger.info(key_passphrase)
|
| 113 | ssh.connect(host, username=username, passphrase='passphrase', key_filename='./ssh/id_otf.key')
|
| 114 | with open('./ssh/id_otf.key', 'r') as myfile:
|
| 115 | data = myfile.read().replace('\n', '')
|
| 116 |
|
| 117 | app.logger.info(data)
|
| 118 | else:
|
| 119 | ssh.connect(host, username=username, password=password)
|
| 120 | command = test_data['command']
|
| 121 | ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(command)
|
| 122 |
|
| 123 | responseData['vthResponse']['resultData']['output'] = str(ssh_stdout.read()).replace('"', '\\"').replace('\n', '\\n')
|
| 124 | responseData['vthResponse']['resultData']['error'] = str(ssh_stderr.read()).replace('"', '\\"').replace('\n', '\\n')
|
| 125 |
|
| 126 | else:
|
| 127 | raise KeyError('Missing vthInput parameter(s)')
|
| 128 |
|
| 129 | # record the end time of the test
|
| 130 | endTime = unix_time_millis(datetime.datetime.now())
|
| 131 |
|
| 132 | # Calculate the total duration of the test
|
| 133 | totalTime = endTime - start_time
|
| 134 |
|
| 135 | # Set the test duration in the result
|
| 136 | responseData['vthResponse']['testDurationMS'] = totalTime
|
| 137 |
|
| 138 | responseData['vthResponse']['abstractMessage'] = 'done'
|
| 139 |
|
| 140 | app.logger.info(str(responseData))
|
| 141 |
|
| 142 | return jsonify(responseData)
|
| 143 | except Exception as e:
|
| 144 | app.logger.info(e)
|
| 145 | responseData['vthResponse']['abstractMessage'] = str(e)
|
| 146 | resp = make_response(json.dumps(responseData))
|
| 147 | endTime = unix_time_millis(datetime.datetime.now())
|
| 148 |
|
| 149 | totalTime = endTime - start_time
|
| 150 | return resp
|
| 151 |
|
| 152 |
|
| 153 | if __name__ == '__main__':
|
| 154 | logHandler = FileHandler('otf/logs/sshVTH.log', mode='a')
|
| 155 | # logHandler = FileHandler('sshVTH.log', mode='a')
|
| 156 | logHandler.setLevel(logging.INFO)
|
| 157 | app.logger.setLevel(logging.INFO)
|
| 158 | app.logger.addHandler(logHandler)
|
| 159 | context = ('opt/cert/otf.pem', 'opt/cert/privateKey.pem')
|
| 160 | app.run(debug = False, host = '0.0.0.0', port = 5000, ssl_context = context)
|
| 161 | # app.run(debug = False, host = '0.0.0.0', port=5000)
|