p3lib 1.1.108__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- p3lib/__init__.py +0 -0
- p3lib/ate.py +108 -0
- p3lib/bokeh_auth.py +363 -0
- p3lib/bokeh_gui.py +845 -0
- p3lib/boot_manager.py +420 -0
- p3lib/conduit.py +145 -0
- p3lib/database_if.py +289 -0
- p3lib/file_io.py +154 -0
- p3lib/gnome_desktop_app.py +146 -0
- p3lib/helper.py +420 -0
- p3lib/json_networking.py +239 -0
- p3lib/login.html +98 -0
- p3lib/mqtt_rpc.py +240 -0
- p3lib/netif.py +226 -0
- p3lib/netplotly.py +223 -0
- p3lib/ngt.py +841 -0
- p3lib/pconfig.py +874 -0
- p3lib/ssh.py +935 -0
- p3lib/table_plot.py +675 -0
- p3lib/uio.py +574 -0
- p3lib-1.1.108.dist-info/LICENSE +21 -0
- p3lib-1.1.108.dist-info/METADATA +34 -0
- p3lib-1.1.108.dist-info/RECORD +24 -0
- p3lib-1.1.108.dist-info/WHEEL +4 -0
p3lib/login.html
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Bokeh App with Login</title>
|
5
|
+
<style>
|
6
|
+
*{
|
7
|
+
margin:0;
|
8
|
+
padding: 0;
|
9
|
+
box-sizing: border-box;
|
10
|
+
}
|
11
|
+
html{
|
12
|
+
height: 100%;
|
13
|
+
}
|
14
|
+
body{
|
15
|
+
font-family: 'Segoe UI', sans-serif;;
|
16
|
+
font-size: 1rem;
|
17
|
+
line-height: 1.6;
|
18
|
+
height: 100%;
|
19
|
+
}
|
20
|
+
p{
|
21
|
+
padding-bottom: 5px;
|
22
|
+
}
|
23
|
+
.wrap {
|
24
|
+
width: 100%;
|
25
|
+
height: 100%;
|
26
|
+
display: flex;
|
27
|
+
justify-content: center;
|
28
|
+
align-items: center;
|
29
|
+
background: #fafafa;
|
30
|
+
}
|
31
|
+
.login-form{
|
32
|
+
width: 350px;
|
33
|
+
margin: 0 auto;
|
34
|
+
border: 1px solid #ddd;
|
35
|
+
padding: 2rem;
|
36
|
+
background: #ffffff;
|
37
|
+
}
|
38
|
+
.form-input{
|
39
|
+
background: #fafafa;
|
40
|
+
border: 1px solid #eeeeee;
|
41
|
+
padding: 12px;
|
42
|
+
width: 100%;
|
43
|
+
}
|
44
|
+
.form-group{
|
45
|
+
margin-bottom: 1rem;
|
46
|
+
}
|
47
|
+
.form-button{
|
48
|
+
background: #69d2e7;
|
49
|
+
border: 1px solid #ddd;
|
50
|
+
color: #ffffff;
|
51
|
+
padding: 10px;
|
52
|
+
width: 100%;
|
53
|
+
text-transform: uppercase;
|
54
|
+
}
|
55
|
+
.form-button:hover{
|
56
|
+
background: #69c8e7;
|
57
|
+
}
|
58
|
+
.form-header{
|
59
|
+
text-align: center;
|
60
|
+
margin-bottom : 2rem;
|
61
|
+
}
|
62
|
+
.form-footer{
|
63
|
+
text-align: center;
|
64
|
+
}
|
65
|
+
</style>
|
66
|
+
</head>
|
67
|
+
<body>
|
68
|
+
<div class="wrap">
|
69
|
+
<form class="login-form" action="/login" method="post">
|
70
|
+
{% module xsrf_form_html() %}
|
71
|
+
<div class="form-header">
|
72
|
+
<h3><img src="https://static.bokeh.org/logos/logotype.svg"></h3>
|
73
|
+
<p> Login to access your application</p>
|
74
|
+
</div>
|
75
|
+
<!--Email Input-->
|
76
|
+
<div class="form-group">
|
77
|
+
<input name="username" type="text" class="form-input" autocapitalize="off" autocorrect="off" placeholder="username">
|
78
|
+
</div>
|
79
|
+
<!--Password Input-->
|
80
|
+
<div class="form-group">
|
81
|
+
<input name="password" type="password" class="form-input" placeholder="password">
|
82
|
+
</div>
|
83
|
+
<!--Login Button-->
|
84
|
+
<div class="form-group">
|
85
|
+
<button class="form-button" type="submit">Login</button>
|
86
|
+
</div>
|
87
|
+
<span class="errormessage">{{errormessage}}</span>
|
88
|
+
<div><small>
|
89
|
+
<p>This is a <b>toy example</b> that demonstrates the authentication building blocks that are available with a Bokeh server.</p>
|
90
|
+
|
91
|
+
<p>You can log in with user: <b><i>bokeh</i></b> / pass: <b><i>bokeh</i></b></p>
|
92
|
+
|
93
|
+
<p><a href="https://docs.bokeh.org/en/latest/docs/user_guide/server/deploy.html#authentication">See the documentation</a> for a full discussion.</p>
|
94
|
+
</small></div>
|
95
|
+
</form>
|
96
|
+
</div>
|
97
|
+
</body>
|
98
|
+
</html>
|
p3lib/mqtt_rpc.py
ADDED
@@ -0,0 +1,240 @@
|
|
1
|
+
#!/usr/bin/python3
|
2
|
+
|
3
|
+
import paho.mqtt.client as mqtt
|
4
|
+
from abc import abstractmethod
|
5
|
+
import json
|
6
|
+
import traceback
|
7
|
+
from threading import Condition
|
8
|
+
from queue import Queue
|
9
|
+
|
10
|
+
class MQTTError(Exception):
|
11
|
+
pass
|
12
|
+
|
13
|
+
class MQTTRPCClient(object):
|
14
|
+
|
15
|
+
DEFAULT_HOST = "localhost"
|
16
|
+
DEFAULT_PORT = 1883
|
17
|
+
DEFAULT_KEEPALIVE_SECONDS = 60
|
18
|
+
DEFAULT_SRV_ID = 1
|
19
|
+
|
20
|
+
CLIENT_ID_DICT_KEY = "SRC"
|
21
|
+
METHOD_DICT_KEY = "METHOD"
|
22
|
+
ARGS_DICT_KEY = "ARGS"
|
23
|
+
RESPONSE_DICT_KEY = "RESPONSE"
|
24
|
+
|
25
|
+
@staticmethod
|
26
|
+
def GetServerRPCTopic(idNumber=1):
|
27
|
+
"""@brief Responsible for getting the Server RPC topic string.
|
28
|
+
@param idNumber The idNumber of the RPC server that RPC messages can be sent to.
|
29
|
+
@return A string that represents the RPC server topic."""
|
30
|
+
return "server%d/RPC" % (idNumber)
|
31
|
+
|
32
|
+
@staticmethod
|
33
|
+
def GetClientID(id=1):
|
34
|
+
"""@brief Responsible for getting a client ID string.
|
35
|
+
@param id The unique id of the MQTT client.
|
36
|
+
@return A string that represents the unique client ID."""
|
37
|
+
return "client%s/RPC" % ( str(id) )
|
38
|
+
|
39
|
+
def __init__(self, uo, options):
|
40
|
+
"""@brief Responsible fopr providing RPC functionality via an MQTT server.
|
41
|
+
@param uo A UO instance that implements the info(text) and error(text) methods
|
42
|
+
to send information to the user.
|
43
|
+
@param options An options instance.
|
44
|
+
options.sid = A number to uniquely identify the server
|
45
|
+
options.cid = A number to uniquely identify the client
|
46
|
+
options.server = The host address of the MQTT server
|
47
|
+
options.port = The port number to connect to the MQTT server
|
48
|
+
options.keepalive = The keepalive period in seconds
|
49
|
+
|
50
|
+
The MQTTRPCClient class can only be a base class and should be extended. Child classes must
|
51
|
+
implement/override the _onMessage() method."""
|
52
|
+
self._uo = uo
|
53
|
+
self._options = options
|
54
|
+
|
55
|
+
self._serverRPCTopic = MQTTRPCClient.GetServerRPCTopic(idNumber=self._options.sid)
|
56
|
+
|
57
|
+
self._client = mqtt.Client()
|
58
|
+
self._client.on_connect = self._onConnect
|
59
|
+
self._client.on_message = self._onMessage
|
60
|
+
|
61
|
+
def connect(self):
|
62
|
+
"""@brief Connect to the MQTT server"""
|
63
|
+
self._client.connect(self._options.server, self._options.port, self._options.keepalive)
|
64
|
+
|
65
|
+
def loopForever(self):
|
66
|
+
"""@brief Wait here to service messages after a successfll connection."""
|
67
|
+
self._client.loop_forever()
|
68
|
+
|
69
|
+
def _onConnect(self, client, userdata, flags, rc):
|
70
|
+
"""@brief Called when connected to the MQTT server."""
|
71
|
+
self._client.subscribe( self._serverRPCTopic )
|
72
|
+
self._uo.info("Connected to MQTT server (%s:%d) and subscribed to %s" % (self._options.server, self._options.port, self._serverRPCTopic) )
|
73
|
+
|
74
|
+
@abstractmethod
|
75
|
+
def _onMessage(self, client, userdata, msg):
|
76
|
+
"""@brief Called when a message is received from the MQTT server.
|
77
|
+
This method mst be implented in a child class."""
|
78
|
+
pass
|
79
|
+
|
80
|
+
class MQTTRPCProviderClient(MQTTRPCClient):
|
81
|
+
|
82
|
+
def __init__(self, uo, options, rpcMethodProviderList):
|
83
|
+
"""@brief Responsible for providing RPC functionality via an MQTT server.
|
84
|
+
MQTTRPCProviderClient instances implement the RPC at the destination/remote side
|
85
|
+
and return the results to the caller side.
|
86
|
+
@param uo A UO instance that implements the info(text) and error(text) methods
|
87
|
+
to send information to the user.
|
88
|
+
@param options An options instance.
|
89
|
+
options.sid = A number to uniquely identify the server
|
90
|
+
options.cid = A number to uniquely identify the client receiving responses from the server.
|
91
|
+
options.server = The host address of the MQTT server
|
92
|
+
options.port = The port number to connect to the MQTT server
|
93
|
+
options.keepalive = The keepalive period in seconds
|
94
|
+
@param rpcMethodProviderList A list/tuple of class instances that provide the RPC methods."""
|
95
|
+
MQTTRPCClient.__init__(self, uo, options)
|
96
|
+
self._rpcMethodProviderList=rpcMethodProviderList
|
97
|
+
|
98
|
+
def _onMessage(self, client, userdata, msg):
|
99
|
+
"""@brief Called when a message is received from the MQTT server.
|
100
|
+
@param client: the client instance for this callback
|
101
|
+
@param userdata: the private user data as set in Client() or userdata_set()
|
102
|
+
@param message: an instance of MQTTMessage.
|
103
|
+
This is a class with members topic, payload, qos, retain."""
|
104
|
+
try:
|
105
|
+
|
106
|
+
rxStr = msg.payload.decode()
|
107
|
+
self._uo.info( "RX: %s" % (rxStr) )
|
108
|
+
|
109
|
+
jsonDict = json.loads( msg.payload.decode() )
|
110
|
+
|
111
|
+
if MQTTRPCClient.CLIENT_ID_DICT_KEY in jsonDict and MQTTRPCClient.METHOD_DICT_KEY in jsonDict:
|
112
|
+
clientID = jsonDict[MQTTRPCClient.CLIENT_ID_DICT_KEY]
|
113
|
+
methodName = jsonDict[MQTTRPCClient.METHOD_DICT_KEY]
|
114
|
+
args = jsonDict[MQTTRPCClient.ARGS_DICT_KEY]
|
115
|
+
|
116
|
+
method = None
|
117
|
+
for rpcMethodProvider in self._rpcMethodProviderList:
|
118
|
+
if hasattr(rpcMethodProvider, methodName):
|
119
|
+
method = getattr(rpcMethodProvider, methodName)
|
120
|
+
|
121
|
+
if method:
|
122
|
+
if len(args) > 0:
|
123
|
+
response = method(args)
|
124
|
+
else:
|
125
|
+
response = method()
|
126
|
+
|
127
|
+
jsonDict[MQTTRPCClient.RESPONSE_DICT_KEY]=response
|
128
|
+
|
129
|
+
jsonString = json.dumps(jsonDict)
|
130
|
+
|
131
|
+
self._uo.info( "TX: %s" % (jsonString) )
|
132
|
+
client.publish(clientID, jsonString)
|
133
|
+
|
134
|
+
else:
|
135
|
+
raise AttributeError("Unable to find a provider of the %s method." % (methodName) )
|
136
|
+
|
137
|
+
except:
|
138
|
+
tb = traceback.format_exc()
|
139
|
+
self._uo.error(tb)
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
class MQTTRPCCallerClient(MQTTRPCClient):
|
144
|
+
|
145
|
+
def __init__(self, uo, options, responseTimeoutSeconds = 10):
|
146
|
+
"""@brief Responsible fopr providing RPC functionality via an MQTT server.
|
147
|
+
MQTTRPCCallerClient instances implement the RPC at the src/caller side
|
148
|
+
sending RPC requests to destination/remote and reciving responses.
|
149
|
+
@param uo A UO instance that implements the info(text) and error(text) methods
|
150
|
+
to send information to the user.
|
151
|
+
@param options An options instance.
|
152
|
+
options.sid = A number to uniquely identify the server responding to RPC calls.
|
153
|
+
options.cid = A number to uniquely identify the client receiving responses from the server.
|
154
|
+
options.server = The host address of the MQTT server
|
155
|
+
options.port = The port number to connect to the MQTT server
|
156
|
+
options.keepalive = The keepalive period in seconds
|
157
|
+
@param timeoutSeconds The number of seconds to wait for a timeout when no response is received."""
|
158
|
+
MQTTRPCClient.__init__(self, uo, options)
|
159
|
+
self._responseTimeoutSeconds = responseTimeoutSeconds
|
160
|
+
|
161
|
+
self._clientSRC = MQTTRPCClient.GetClientID(options.cid)
|
162
|
+
|
163
|
+
self._serverRPCTopic = MQTTRPCClient.GetServerRPCTopic(idNumber=self._options.sid)
|
164
|
+
|
165
|
+
self._sendMsgDict = None
|
166
|
+
self._responseQueue = Queue()
|
167
|
+
|
168
|
+
self._condition = Condition()
|
169
|
+
|
170
|
+
def _onMessage(self, client, userdata, msg):
|
171
|
+
"""@brief Called when a message is received from the MQTT server.
|
172
|
+
@param client: the client instance for this callback
|
173
|
+
@param userdata: the private user data as set in Client() or userdata_set()
|
174
|
+
@param message: an instance of MQTTMessage.
|
175
|
+
This is a class with members topic, payload, qos, retain.
|
176
|
+
@return None"""
|
177
|
+
try:
|
178
|
+
|
179
|
+
responseDict = json.loads( msg.payload.decode() )
|
180
|
+
if responseDict and MQTTRPCClient.RESPONSE_DICT_KEY in responseDict:
|
181
|
+
self._condition.acquire()
|
182
|
+
self._responseQueue.put(responseDict[MQTTRPCClient.RESPONSE_DICT_KEY])
|
183
|
+
self._condition.notify()
|
184
|
+
self._condition.release()
|
185
|
+
|
186
|
+
except:
|
187
|
+
tb = traceback.format_exc()
|
188
|
+
self._uo.error(tb)
|
189
|
+
|
190
|
+
def _getResponse(self):
|
191
|
+
"""@brief Internal method used to get the response to an RPC
|
192
|
+
@return The response to the RPC or None if a timeout occurs."""
|
193
|
+
|
194
|
+
# blocks until the response is processed or a timeout occurs
|
195
|
+
self._condition.wait(timeout=self._responseTimeoutSeconds)
|
196
|
+
|
197
|
+
response = None
|
198
|
+
if not self._responseQueue.empty():
|
199
|
+
response = self._responseQueue.get()
|
200
|
+
|
201
|
+
return response
|
202
|
+
|
203
|
+
def _getRPCString(self):
|
204
|
+
"""@brief Get the last RPC called as a string.
|
205
|
+
@return The RPC string representation."""
|
206
|
+
if self._sendMsgDict and MQTTRPCClient.METHOD_DICT_KEY in self._sendMsgDict and MQTTRPCClient.ARGS_DICT_KEY in self._sendMsgDict:
|
207
|
+
return "%s(%s)" % (self._sendMsgDict[MQTTRPCClient.METHOD_DICT_KEY], self._sendMsgDict[MQTTRPCClient.ARGS_DICT_KEY])
|
208
|
+
else:
|
209
|
+
return ""
|
210
|
+
|
211
|
+
def rpcCall(self, methodName, argList):
|
212
|
+
"""@brief Call an RPC
|
213
|
+
@param methodName The name of the RPC to call. Currently this is just the method name.
|
214
|
+
This method could exist on an instance of any object. We could have
|
215
|
+
made this include instance details but to keep things simple
|
216
|
+
just the method name is provided.
|
217
|
+
@param argList The arguments for the RPC
|
218
|
+
@return The response to the RPC."""
|
219
|
+
self._sendMsgDict={}
|
220
|
+
self._sendMsgDict[MQTTRPCClient.CLIENT_ID_DICT_KEY]=self._clientSRC
|
221
|
+
self._sendMsgDict[MQTTRPCClient.METHOD_DICT_KEY]=methodName
|
222
|
+
self._sendMsgDict[MQTTRPCClient.ARGS_DICT_KEY]=argList
|
223
|
+
|
224
|
+
jsonDict = json.dumps(self._sendMsgDict, indent=4, sort_keys=True)
|
225
|
+
|
226
|
+
self._client.subscribe(self._clientSRC)
|
227
|
+
|
228
|
+
self._condition.acquire()
|
229
|
+
|
230
|
+
response = None
|
231
|
+
try:
|
232
|
+
self._client.publish(self._serverRPCTopic, jsonDict)
|
233
|
+
|
234
|
+
response = self._getResponse()
|
235
|
+
|
236
|
+
finally:
|
237
|
+
|
238
|
+
self._condition.release()
|
239
|
+
|
240
|
+
return response
|
p3lib/netif.py
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
#!/usr/bin/env python3.8
|
2
|
+
|
3
|
+
import platform
|
4
|
+
from subprocess import check_output
|
5
|
+
import socket
|
6
|
+
import struct
|
7
|
+
|
8
|
+
class NetIF(object):
|
9
|
+
"""@Responsible for determining details about the network interfaces on a PC."""
|
10
|
+
|
11
|
+
LINUX_OS_NAME = "Linux"
|
12
|
+
SUPPORTED_OS_NAMES = [ LINUX_OS_NAME ]
|
13
|
+
|
14
|
+
ID_STR1 = "inet addr:"
|
15
|
+
ID_STR2 = "addr:"
|
16
|
+
ID_STR3 = "mask:"
|
17
|
+
ID_STR4 = "inet "
|
18
|
+
|
19
|
+
IP_NETMASK_SEP = "/"
|
20
|
+
|
21
|
+
@staticmethod
|
22
|
+
def IsAddressInNetwork(ip, net):
|
23
|
+
"""@brief Determine if an IP address is in a IP network.
|
24
|
+
@param ip The IP address of the interface in the format 192.168.1.20
|
25
|
+
@param net The network in the format 192.168.1.0/24"""
|
26
|
+
ipaddr = socket.inet_aton(ip)
|
27
|
+
netaddr, netmask = net.split(NetIF.IP_NETMASK_SEP)
|
28
|
+
netaddr = socket.inet_aton(netaddr)
|
29
|
+
|
30
|
+
ipint = struct.unpack("!I", ipaddr)[0]
|
31
|
+
netint = struct.unpack("!I", netaddr)[0]
|
32
|
+
maskint = (0xFFFFFFFF << (32 - int(netmask))) & 0xFFFFFFFF
|
33
|
+
|
34
|
+
return ipint & maskint == netint
|
35
|
+
|
36
|
+
|
37
|
+
@staticmethod
|
38
|
+
def IPStr2int(addr):
|
39
|
+
"""@brief Convert an IP address string to an integer.
|
40
|
+
@param addr The IP address string.
|
41
|
+
@return The integer represented by the IP address."""
|
42
|
+
return struct.unpack("!I", socket.inet_aton(addr))[0]
|
43
|
+
|
44
|
+
@staticmethod
|
45
|
+
def Int2IPStr(addr):
|
46
|
+
"""@brief Convert an integer to an IP address string.
|
47
|
+
@param addr The Integer value of the IP address.
|
48
|
+
@return The string value (dotted quad) of the IP address."""
|
49
|
+
return socket.inet_ntoa(struct.pack("!I", addr))
|
50
|
+
|
51
|
+
@staticmethod
|
52
|
+
def NetmaskToBitCount(netmask):
|
53
|
+
"""@brief Convert a dotted quad netmask to a bit count netmask format.
|
54
|
+
@param netmask: The dotted quad netmask (E.G 255.255.255.0)
|
55
|
+
@return: The netmask as a count of the set bits (E.G 24).
|
56
|
+
"""
|
57
|
+
return sum([bin(int(x)).count('1') for x in netmask.split('.')])
|
58
|
+
|
59
|
+
@staticmethod
|
60
|
+
def BitCountToNetMask(bitCount):
|
61
|
+
"""@brief Convert a bit count to a netmask string
|
62
|
+
@param bitCount The number of bits in the netmask.
|
63
|
+
@return The netmask string E.G 255.255.255.0"""
|
64
|
+
if bitCount > 32:
|
65
|
+
raise Exception("{} greater than 32".format(bitCount))
|
66
|
+
num=1
|
67
|
+
for _ in range(0,bitCount):
|
68
|
+
num=num>>1
|
69
|
+
num=num|0x80000000
|
70
|
+
return NetIF.Int2IPStr(num)
|
71
|
+
|
72
|
+
def __init__(self):
|
73
|
+
|
74
|
+
self._osName = platform.system()
|
75
|
+
|
76
|
+
self._checkSupportedOS()
|
77
|
+
|
78
|
+
self._ifDict = None
|
79
|
+
|
80
|
+
def getLocalNetworkAddress(self):
|
81
|
+
"""@brief Get the IP address of the local interface that has the default route.
|
82
|
+
The IP address will be the source IP address for packets are sent over the default route from this machine.
|
83
|
+
This works on Windows, Linux, Android"""
|
84
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
85
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
86
|
+
sock.connect(('<broadcast>', 0))
|
87
|
+
netIPAddr = sock.getsockname()[0]
|
88
|
+
sock.close()
|
89
|
+
return netIPAddr
|
90
|
+
|
91
|
+
def getIFDict(self, readNow=False, includeNoIPIF = False):
|
92
|
+
"""@param readNow If True the read the current network interface
|
93
|
+
state now regardless of wether we have read it previously.
|
94
|
+
If False and we have read the state of the network
|
95
|
+
interfaces previously then return the previous state.
|
96
|
+
@param includeNoIPIF If True then interfaces with no IPaddress are included in the results.
|
97
|
+
@return A dict of the IP network interfaces on this platform.
|
98
|
+
key = name of interface
|
99
|
+
value = A list of <IP ADDRESS>/<NET MASK BIT COUNT>"""
|
100
|
+
if self._ifDict and not readNow:
|
101
|
+
return self._ifDict
|
102
|
+
|
103
|
+
if self._osName.find(NetIF.LINUX_OS_NAME) >= 0 :
|
104
|
+
self._ifDict = self.getLinuxIFDict(includeNoIPIF=includeNoIPIF)
|
105
|
+
|
106
|
+
return self._ifDict
|
107
|
+
|
108
|
+
def getLinuxIFDict(self, includeNoIPIF = False):
|
109
|
+
"""@brief Get a dic that contains the local interface details.
|
110
|
+
@param includeNoIPIF If True then interfaces with no IPaddress are included in the results.
|
111
|
+
@return A dict of the IP network interfaces on this platform.
|
112
|
+
key = name of interface
|
113
|
+
value = A list of <IP ADDRESS>/<NET MASK BIT COUNT>"""
|
114
|
+
netIFDict = {}
|
115
|
+
|
116
|
+
cmdOutput = check_output(['/sbin/ip','a'] ).decode()
|
117
|
+
netIFDict = self._getLinuxIFDict(cmdOutput, includeNoIPIF=includeNoIPIF)
|
118
|
+
return netIFDict
|
119
|
+
|
120
|
+
def _getLinuxIFDict(self, cmdOutput, includeNoIPIF=False):
|
121
|
+
"""@brief Get a dic that contains the local interface details.
|
122
|
+
@param cmdOutput The ip a command output.
|
123
|
+
@param includeNoIPIF If True then interfaces with no IPaddress are included in the results.
|
124
|
+
@return A dict of the IP network interfaces on this platform.
|
125
|
+
key = name of interface
|
126
|
+
value = A list of <IP ADDRESS>/<NET MASK BIT COUNT>"""
|
127
|
+
netIFDict = {}
|
128
|
+
lines = cmdOutput.lower().split('\n')
|
129
|
+
ifName = None
|
130
|
+
ifAddressList = []
|
131
|
+
for line in lines:
|
132
|
+
elems = line.split(":")
|
133
|
+
try:
|
134
|
+
#If first element is the IF ID
|
135
|
+
#Note that the IF ID may not be sequential
|
136
|
+
int(elems[0])
|
137
|
+
#Extract the if name
|
138
|
+
if len(elems) > 1:
|
139
|
+
ifName = elems[1].strip()
|
140
|
+
ifName = ifName.replace(":", "")
|
141
|
+
ifAddressList = []
|
142
|
+
if includeNoIPIF:
|
143
|
+
netIFDict[ifName] = ifAddressList
|
144
|
+
except:
|
145
|
+
line = line.strip()
|
146
|
+
if line.startswith("inet "):
|
147
|
+
elems = line.split()
|
148
|
+
if len(elems) > 1:
|
149
|
+
ipAddress = elems[1]
|
150
|
+
ifAddressList.append(ipAddress)
|
151
|
+
netIFDict[ifName] = ifAddressList
|
152
|
+
|
153
|
+
return netIFDict
|
154
|
+
|
155
|
+
def getIFName(self, ipAddress):
|
156
|
+
"""@brief Get the name of the interface which the ip address can be reached directly (not via an IP gateway)
|
157
|
+
@param ipAddress The IP address that should be out on an interface.
|
158
|
+
@return The dict entry for the interface.
|
159
|
+
key == Interface name
|
160
|
+
value = Interface address.
|
161
|
+
@return The name of the local network interface or None if not found."""
|
162
|
+
ifDict = self.getIFDict()
|
163
|
+
ifNames = list(ifDict.keys())
|
164
|
+
ifNames.sort()
|
165
|
+
for ifName in ifNames:
|
166
|
+
ipDetailsList = ifDict[ifName]
|
167
|
+
for ipDetails in ipDetailsList:
|
168
|
+
elems = ipDetails.split(NetIF.IP_NETMASK_SEP)
|
169
|
+
if len(elems) == 2:
|
170
|
+
ipAddr = elems[0]
|
171
|
+
netMaskBits= int(elems[1])
|
172
|
+
netMask = NetIF.BitCountToNetMask(netMaskBits)
|
173
|
+
ipAddrInt = NetIF.IPStr2int(ipAddr)
|
174
|
+
netMaskInt = NetIF.IPStr2int(netMask)
|
175
|
+
network = ipAddrInt&netMaskInt
|
176
|
+
networkStr = socket.inet_ntoa(struct.pack("!I", network))
|
177
|
+
netMaskInt=24
|
178
|
+
if NetIF.IsAddressInNetwork(ipAddress, "%s/%s" % ( networkStr, netMaskInt) ):
|
179
|
+
return ifName
|
180
|
+
|
181
|
+
return None
|
182
|
+
|
183
|
+
def _getIFDetails(self, ifName):
|
184
|
+
"""@brief Get the details of the network interface on this machine given the interface name.
|
185
|
+
@param ifName The name of the interface.
|
186
|
+
@return A tuple containing the tuples that contain
|
187
|
+
0: IP address
|
188
|
+
1: Netmask"""
|
189
|
+
self.getIFDict()
|
190
|
+
if ifName in self._ifDict:
|
191
|
+
ifDetailsList = self._ifDict[ifName]
|
192
|
+
for ifDetails in ifDetailsList:
|
193
|
+
if ifDetails:
|
194
|
+
elems = ifDetails.split(NetIF.IP_NETMASK_SEP)
|
195
|
+
if len(elems) == 2:
|
196
|
+
return elems
|
197
|
+
return None
|
198
|
+
|
199
|
+
def getIFIPAddress(self, ifName):
|
200
|
+
"""@brief Get the IP address of the network interface on this machine given the interface name.
|
201
|
+
@param ifName The name of the interface.
|
202
|
+
@return The IP address oft heinterface of None if unknown."""
|
203
|
+
ifDetails = self._getIFDetails(ifName)
|
204
|
+
if ifDetails and len(ifDetails) == 2:
|
205
|
+
return ifDetails[0]
|
206
|
+
|
207
|
+
return None
|
208
|
+
|
209
|
+
def getIFNetmask(self, ifName):
|
210
|
+
"""@brief Get the netmask of the network interface on this machine given the interface name.
|
211
|
+
@param ifName The name of the interface.
|
212
|
+
@return The IP address of the interface of None if unknown."""
|
213
|
+
ifDetails = self._getIFDetails(ifName)
|
214
|
+
if ifDetails and len(ifDetails) == 2:
|
215
|
+
netMaskBitCount = int(ifDetails[1])
|
216
|
+
return NetIF.BitCountToNetMask(netMaskBitCount)
|
217
|
+
|
218
|
+
return None
|
219
|
+
|
220
|
+
def _checkSupportedOS(self):
|
221
|
+
"""@brief Check that the OS is supported."""
|
222
|
+
for supportedOSName in NetIF.SUPPORTED_OS_NAMES:
|
223
|
+
if self._osName.find(supportedOSName) != -1:
|
224
|
+
return
|
225
|
+
|
226
|
+
raise Exception("%s: %s is an unsupported platform", type(self).__name__, self._osName)
|