blob: 757db8b74c29aa0ae4d635929bc85d2480d48f60 [file] [log] [blame]
Hyunsun Moon4506e3e2020-10-07 01:27:12 +00001#!/usr/bin/env python3
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -07002
3# Copyright 2020-present Open Networking Foundation
4#
Andy Bavier200bd272022-06-09 11:15:51 -07005# SPDX-License-Identifier: Apache-2.0
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -07006
Hyunsun Moon4506e3e2020-10-07 01:27:12 +00007import sys
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -07008import os
9import time
10import requests
11import json
12import enum
Hyunsun Moon4506e3e2020-10-07 01:27:12 +000013import logging
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070014from collections import namedtuple
15from pyadb import ADB
16
17'''
18Check Aether network operational status and report it to
19central monitoring server
20
211) check mobile connctivity after toggling the airplane mode
222) check if ping to 8.8.8.8 works
23'''
24
25CONF = json.loads(
26 open(os.getenv('CONFIG_FILE', "./config.json")).read(),
27 object_hook=lambda d: namedtuple('X', d.keys())(*d.values())
28)
29
Hyunsun Moon4506e3e2020-10-07 01:27:12 +000030logging.basicConfig(
31 filename=CONF.log_file,
32 format='%(asctime)s [%(levelname)s] %(message)s',
33 level=logging.WARN
34)
35
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070036ADB_GET_COMMANDS = {
37 "apn_mode": "settings get global airplane_mode_on",
38 "lte_state": "dumpsys telephony.registry | grep -m1 mDataConnectionState",
Jeremy Ronquillod996b512021-02-13 13:45:47 -080039 "ping_result": "ping -c 3 8.8.8.8&>/dev/null; echo $?",
40 "ping_dns_result": "ping -c 10 " + "8.8.8.8" +
41 " | tail -1 | awk '{print $4}'"
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070042}
43ADB_APN_COMMANDS = {
44 "home": "input keyevent 3",
45 "setting": "am start -a android.settings.AIRPLANE_MODE_SETTINGS",
46 "toggle": "input tap " + \
47 CONF.adb.apn_mode_toggle_location.x + " " + \
48 CONF.adb.apn_mode_toggle_location.y
49}
50
51
52class State(enum.Enum):
53 error = "-1"
54 disconnected = "0"
55 connecting = "1"
56 connected = "2"
57
58 @classmethod
59 def has_value(cls, value):
60 return value in cls._value2member_map_
61
62
63edge_status = {
64 'name': CONF.edge_name,
65 'status': {
66 'control_plane': None,
67 'user_plane': 'connected'
Jeremy Ronquillod996b512021-02-13 13:45:47 -080068 },
69 'speedtest': {
70 'ping': {
71 'dns': {
Jeremy Ronquilloa944fbc2021-03-30 10:57:45 -070072 'min': 0.0,
73 'avg': 0.0,
74 'max': 0.0,
75 'stddev': 0.0
Jeremy Ronquillod996b512021-02-13 13:45:47 -080076 }
77 }
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070078 }
79}
80
81
82def _run_adb_shell(adb, command):
Hyunsun Moon53097ea2020-09-04 17:20:29 -070083 result, error = adb.shell_command(command)
Hyunsun Moon4506e3e2020-10-07 01:27:12 +000084 # error is returned even when succeeded
85 # so ignore error value here
86 if result:
87 logging.debug(result)
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070088 time.sleep(2)
89 result = result[0] if result is not None else None
90 return True, result
91
92
Hyunsun Moon53097ea2020-09-04 17:20:29 -070093def get_control_plane_state(adb):
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070094 '''
95 check aether control plane works by toggling airplane mode
96 '''
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -070097 # get the current airplane mode
98 success, result = _run_adb_shell(adb, ADB_GET_COMMANDS['apn_mode'])
99 if not success or result is None:
100 return State.error, result
101 apn_mode_on = True if result == "1" else False
102
103 # toggle the airplane mode
104 for command in ADB_APN_COMMANDS.values():
105 success, result = _run_adb_shell(adb, command)
106 if not success:
107 return State.error, result
108 if not apn_mode_on:
109 success, result = _run_adb_shell(adb, ADB_APN_COMMANDS['toggle'])
110 if not success:
111 return State.error, result
112
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700113 # get connection state
114 state = State.connecting.value
Hyunsun Moona40bda52021-01-21 12:04:43 -0800115 retry_count = 10
116 while retry_count > 0:
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700117 success, result = _run_adb_shell(adb, ADB_GET_COMMANDS['lte_state'])
118 if not success or result is None:
Hyunsun Moona40bda52021-01-21 12:04:43 -0800119 continue
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700120 state = result.split("=")[1]
Hyunsun Moona40bda52021-01-21 12:04:43 -0800121 if state == State.connected.value:
122 break
Hyunsun Moon659f2812021-01-21 13:43:49 -0800123 time.sleep(1)
Hyunsun Moona40bda52021-01-21 12:04:43 -0800124 retry_count -= 1
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700125
126 if not State.has_value(state):
127 return State.error, None
128 return State(state), None
129
130
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700131def get_user_plane_state(adb):
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700132 '''
133 checks aether user plane connectivity with ping to 8.8.8.8
134 '''
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700135 success, result = _run_adb_shell(adb, ADB_GET_COMMANDS['ping_result'])
136 if not success or result is None:
137 return State.error, result
138
139 state = State.connected if result == "0" else State.disconnected
140 return state, None
141
142
Jeremy Ronquillod996b512021-02-13 13:45:47 -0800143def run_ping_test(adb, ip, count):
144 '''
145 Runs the ping test
146 Input: IP to ping, # times to ping
147 Returns: dict of the min/avg/max/stddev numbers from the ping command result
148 '''
Jeremy Ronquilloa944fbc2021-03-30 10:57:45 -0700149 result = {'min': 0.0,
150 'avg': 0.0,
151 'max': 0.0,
152 'stddev': 0.0}
Jeremy Ronquillod996b512021-02-13 13:45:47 -0800153 try:
154 commandResult, commandOutput = _run_adb_shell(adb, ADB_GET_COMMANDS['ping_dns_result'])
155 pingResult = commandOutput.split("/")
156 result = {'min': float(pingResult[0]),
157 'avg': float(pingResult[1]),
158 'max': float(pingResult[2]),
159 'stddev': float(pingResult[3])}
160 except Exception as e:
161 logging.error("Ping test failed for " + ip + ": %s", e)
162 return result
163
164
165def get_ping_test(adb):
166 '''
167 Each ping test result saves the min/avg/max/stddev to dict.
168 1) Performs ping test to Google Public DNS for 10 iterations.
169 2) # TODO: Performs ping to device on network.
170 '''
171 speedtest_ping = {}
172 speedtest_ping['dns'] = run_ping_test(adb, "8.8.8.8", 10)
173 return speedtest_ping
174
175
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700176def report_aether_network_state():
177 '''
178 report the aether network state to the monitoring server
179 '''
Hyunsun Moon4506e3e2020-10-07 01:27:12 +0000180 logging.info("Sending report %s", edge_status)
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700181 try:
182 result = requests.post(CONF.report_url, json=edge_status)
183 except requests.exceptions.ConnectionError:
Hyunsun Moon4506e3e2020-10-07 01:27:12 +0000184 logging.error("Failed to report for %s", e)
185 pass
186 try:
187 result.raise_for_status()
188 except requests.exceptions.HTTPError as e:
189 logging.error("Failed to report for %s", e)
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700190 pass
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700191
192
Hyunsun Moon4506e3e2020-10-07 01:27:12 +0000193def main():
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700194 adb = ADB()
195 if adb.set_adb_path(CONF.adb.path) is False:
Hyunsun Moon4506e3e2020-10-07 01:27:12 +0000196 logging.error(CONF.adb.path + " not found")
197 sys.exit(1)
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700198
199 dev = adb.get_devices()
200 if len(dev) == 0:
Hyunsun Moon4506e3e2020-10-07 01:27:12 +0000201 logging.error("No device found")
202 sys.exit(1)
203
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700204 adb.set_target_device(dev[0])
Hyunsun Moon4506e3e2020-10-07 01:27:12 +0000205 success, result = _run_adb_shell(adb, "svc data enable")
206 if not success:
207 logging.error("Failed to turn data on")
208 sys.exit(1)
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700209
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700210 while True:
Hyunsun Moonda22c762021-01-22 13:00:24 -0800211 _run_adb_shell(adb, "svc power stayon true")
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700212 cp_state, err = get_control_plane_state(adb)
213 up_state, err = get_user_plane_state(adb)
Jeremy Ronquillod996b512021-02-13 13:45:47 -0800214 speedtest_ping = get_ping_test(adb)
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700215
216 edge_status['status']['control_plane'] = cp_state.name
217 edge_status['status']['user_plane'] = up_state.name
Jeremy Ronquillod996b512021-02-13 13:45:47 -0800218 edge_status['speedtest']['ping'] = speedtest_ping
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700219
220 report_aether_network_state()
Hyunsun Moonda22c762021-01-22 13:00:24 -0800221 _run_adb_shell(adb, "svc power stayon false")
222
Hyunsun Moon53097ea2020-09-04 17:20:29 -0700223 time.sleep(CONF.report_interval)
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700224
225
Hyunsun Moonf32ae9a2020-05-28 13:17:45 -0700226if __name__ == "__main__":
227 main()