wlan_monitor.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 import re
18 import os
19 import getpass
20 import traceback
21 import paramiko
22 from subprocess import Popen, PIPE
23 from packaging import version
24 
25 import rospy
26 from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus, KeyValue
27 
28 class IwConfigParser(object):
29  def _parse_info(self, info):
30  values = []
31  # split by either double-space or newline
32  for information in re.split(" |\n",info):
33  # split by either : or =
34  content = re.split(":|=", information)
35  if len(content) == 2:
36  try:
37  content[0] = content[0].decode() #python3
38  content[1] = content[1].decode() #python3
39  except (UnicodeDecodeError, AttributeError):
40  pass
41  values.append(KeyValue(content[0].lstrip(), content[1].rstrip()))
42  return values
43 
45  def __init__(self):
46  IwConfigParser.__init__(self)
47 
48  self.interfaces = []
49  self.stat = DiagnosticStatus()
50  self.stat.level = DiagnosticStatus.OK
51  self.stat.message = "OK"
52  self.stat.values = []
53  try:
54  p = Popen("iw dev | awk '$1==\"Interface\"{print $2}'", stdout=PIPE, stdin=PIPE, stderr=PIPE, shell=True)
55  res = p.wait()
56  (stdout,stderr) = p.communicate()
57  try:
58  stdout = stdout.decode() #python3
59  except (UnicodeDecodeError, AttributeError):
60  pass
61  self.interfaces = sorted(os.linesep.join([s for s in stdout.splitlines() if s]).split('\n'))
62  except Exception as e:
63  message = "IwConfigLocal init exception: %s" % e
64  self.stat.level = DiagnosticStatus.ERROR
65  self.stat.message = message
66  self.stat.values = [ KeyValue(key = 'Exception', value = str(e)), KeyValue(key = 'Traceback', value = str(traceback.format_exc())) ]
67  rospy.logerr(message)
68 
69  def update(self):
70  self.stat.level = DiagnosticStatus.OK
71  self.stat.message = "OK"
72  self.stat.values = []
73  for interface in self.interfaces:
74  self.stat.values.append(KeyValue(key = str(interface), value = "======================="))
75  try:
76  p = Popen(["iwconfig", interface], stdout=PIPE, stdin=PIPE, stderr=PIPE)
77  res = p.wait()
78  (stdout,stderr) = p.communicate()
79  try:
80  stdout = stdout.decode() #python3
81  except (UnicodeDecodeError, AttributeError):
82  pass
83 
84  if res != 0:
85  self.stat.values.append(KeyValue(key = 'iwconfig stderr', value = stderr))
86  self.stat.values.append(KeyValue(key = 'iwconfig stdout', value = stdout))
87  else:
88  self.stat.values += self._parse_info(stdout)
89  except Exception as e:
90  message = "IwConfigLocal update exception: %s" % e
91  self.stat.level = DiagnosticStatus.ERROR
92  self.stat.message = message
93  self.stat.values = [ KeyValue(key = 'Exception', value = str(e)), KeyValue(key = 'Traceback', value = str(traceback.format_exc())) ]
94  rospy.logerr(message)
95 
97  def __init__(self, hostname, user, password):
98  IwConfigParser.__init__(self)
99 
100  self.hostname = str(hostname)
101  self.user = user
102  self.password = password
103  self.ssh = paramiko.SSHClient()
104  self.ssh.load_system_host_keys()
105  self.ssh_key_file = os.getenv("HOME")+'/.ssh/id_rsa.pub'
106  self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())# no known_hosts error
107  self.connect()
108 
109  self.interfaces = []
110  self.stat = DiagnosticStatus()
111  self.stat.level = DiagnosticStatus.OK
112  self.stat.message = "OK"
113  self.stat.values = []
114  try:
115  (stdin, stdout, stderr) = self.ssh.exec_command("iw dev | awk '$1==\"Interface\"{print $2}'")
116  output = ''.join(stdout.readlines())
117  self.interfaces = sorted(os.linesep.join([s for s in output.splitlines() if s]).split('\n'))
118  except Exception as e:
119  message = "IwConfigSSH init exception: %s" % e
120  self.stat.level = DiagnosticStatus.ERROR
121  self.stat.message = message
122  self.stat.values = [ KeyValue(key = 'Exception', value = str(e)), KeyValue(key = 'Traceback', value = str(traceback.format_exc())) ]
123  rospy.logerr(message)
124 
125  def connect(self):
126  if version.parse(paramiko.__version__) < version.parse("2.11.0"):
127  self.ssh.connect(
128  self.hostname,
129  username=self.user,
130  key_filename=self.ssh_key_file,
131  ) # no passwd needed
132  else:
133  self.ssh.connect( # pylint: disable=unexpected-keyword-arg
134  self.hostname,
135  username=self.user,
136  key_filename=self.ssh_key_file,
137  disabled_algorithms={"pubkeys": ["rsa-sha2-256", "rsa-sha2-512"]}
138  ) # no passwd needed
139 
140  def update(self):
141  self.stat.level = DiagnosticStatus.OK
142  self.stat.message = "OK"
143  self.stat.values = []
144 
145  # Reconnect if connection is not active
146  if self.ssh.get_transport() is None or not self.ssh.get_transport().is_active():
147  try:
148  self.connect()
149  except Exception as e:
150  message = "IwConfigSSH connect exception: %s" % e
151  self.stat.level = DiagnosticStatus.ERROR
152  self.stat.message = message
153  self.stat.values = [ KeyValue(key = 'Exception', value = str(e)), KeyValue(key = 'Traceback', value = str(traceback.format_exc())) ]
154  rospy.logerr(message)
155  return
156 
157  for interface in self.interfaces:
158  self.stat.values.append(KeyValue(key = str(interface), value = "======================="))
159  try:
160  (stdin, stdout, stderr) = self.ssh.exec_command("iwconfig %s" % interface)
161  output = ''.join(stdout.readlines())
162  self.stat.values += self._parse_info(output)
163  except Exception as e:
164  message = "IwConfigSSH update exception: %s" % e
165  self.stat.level = DiagnosticStatus.ERROR
166  self.stat.message = message
167  self.stat.values = [ KeyValue(key = 'Exception', value = str(e)), KeyValue(key = 'Traceback', value = str(traceback.format_exc())) ]
168  rospy.logerr(message)
169 
170 class WlanMonitor():
171  def __init__(self):
172  rospy.init_node("wlan_monitor")
173  self.get_params()
174 
175  self._wlan_stat = DiagnosticStatus()
176  self._wlan_stat.name = '%s WLAN Info' % self.diag_hostname
177  self._wlan_stat.hardware_id = self.diag_hostname
178  self._wlan_stat.level = DiagnosticStatus.OK
179  self._wlan_stat.message = 'No Data'
180  self._wlan_stat.values = []
181  self.msg = DiagnosticArray()
182  self.msg.header.stamp = rospy.get_rostime()
183  self.msg.status = [self._wlan_stat]
184 
185  self.diag_pub = rospy.Publisher("/diagnostics", DiagnosticArray, queue_size=1)
186  self.diag_timer = rospy.Timer(rospy.Duration(1.0), self.publish_diagnostics)
187 
188  if self.monitor_local:
190  else:
191  try:
192  self.iwconfig = IwConfigSSH(self.diag_hostname, self.user, self.password)
193  except Exception as e:
194  msg = "Cannot connect to router via ssh. Please check if ssh key of user '{}' is contained in the router configuration or password is provided. Error message: {}".format(getpass.getuser(), e)
195  rospy.logerr(msg)
196  self._wlan_stat.level = DiagnosticStatus.ERROR
197  self._wlan_stat.message = msg
198  self._wlan_stat.values = [ KeyValue(key = 'Exception', value = str(e)), KeyValue(key = 'Traceback', value = str(traceback.format_exc())) ]
199  self.msg.status = [self._wlan_stat]
200  return
201 
202  self.monitor_timer = rospy.Timer(rospy.Duration(1.0), self.update_diagnostics)
203 
204  def update_diagnostics(self, event):
205  self.iwconfig.update()
206 
207  self.msg = DiagnosticArray()
208  self.msg.header.stamp = rospy.get_rostime()
209  self._wlan_stat.level = self.iwconfig.stat.level
210  self._wlan_stat.message = self.iwconfig.stat.message
211  self._wlan_stat.values = self.iwconfig.stat.values
212  self.msg.status = [self._wlan_stat]
213 
214  def publish_diagnostics(self, event):
215  self.diag_pub.publish(self.msg)
216 
217  def get_params(self):
218  self.diag_hostname = rospy.get_param('~diag_hostname', "localhost")
219  self.monitor_local = rospy.get_param("~monitor_local", True)
220  self.user = rospy.get_param('~user', "")
221  self.password = rospy.get_param('~password', "")
222 
223 if __name__ == "__main__":
224  monitor = WlanMonitor()
225  rospy.spin()
def update_diagnostics(self, event)
def _parse_info(self, info)
Definition: wlan_monitor.py:29
def publish_diagnostics(self, event)
def __init__(self, hostname, user, password)
Definition: wlan_monitor.py:97


cob_monitoring
Author(s): Florian Weisshardt , Felix Messmer
autogenerated on Tue May 2 2023 02:26:09