Skip to content

Commit 71e3604

Browse files
moto-timoEmantor
authored andcommitted
driver: digitalloggers_restapi: enable REST API
The legacy HTTP API does not work on newer units without manually changing the configuration in Setup. This driver is based on https://www.digital-loggers.com/restapi.pdf Curl examples that were used for development are included as comments so that users can test their access outside of labgrid. The REST API seems to only allow authenticated users, so the host: parameter is parsed to pass user and password to HTTPDigestAuth. CSRF is also required, so a valid (simple) header is provided. Non-authenticated URLs are supported, but most likely will not work. HTTPS is recommended, but the units ship with self-signed certificates so SSL certificate verification warnings are intentionally ignored. Add to test_powerdriver.py import test. Example usage in lg-env.yaml (default as-shipped settings): NetworkPowerPort: model: 'digitalloggers_restapi' host: 'http://admin:1234@192.168.0.100' index: 0 Signed-off-by: Tim Orling <tim.orling@konsulko.com> [r.czerwinski@pengutronix.de: removed unused and sorted imports] Signed-off-by: Rouven Czerwinski <r.czerwinski@pengutronix.de>
1 parent d4d8370 commit 71e3604

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

doc/configuration.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ Currently available are:
163163
host argument must include the protocol, such as
164164
``http://192.168.0.3`` or ``http://admin:pass@192.168.0.4``.
165165

166+
``digitalloggers_restapi``
167+
Controls *Digital Loggers PDUs* that use the REST API. Note that
168+
host argument must include the protocol, such as
169+
``http://192.168.0.3`` or ``https://admin:pass@192.168.0.4``.
170+
By default, only authenticated users may access the REST API.
171+
HTTPS queries intentially ignore ssl certificate validation, since
172+
the as-shipped certificate is self-signed.
173+
166174
``eaton``
167175
Controls *Eaton ePDUs* via SNMP.
168176

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'''
2+
Driver for Digital Loggers PDU that use the REST API.
3+
Tested with Ethernet Power Controller 7.
4+
5+
Based on https://www.digital-loggers.com/restapi.pdf
6+
7+
By default, only an authenticated user is allowed by REST API.
8+
9+
NetworkPowerPort:
10+
model: 'digitalloggers_restapi'
11+
host: 'http://admin:1234@192.168.0.100'
12+
index: 0
13+
'''
14+
from urllib.parse import urlparse
15+
16+
import requests
17+
from requests.auth import HTTPDigestAuth
18+
from requests.packages import urllib3
19+
20+
21+
def extract_user_password_from_host(host):
22+
url = urlparse(host)
23+
if '@' in url.netloc:
24+
user=url.username
25+
password=url.password
26+
_host= f'{url.scheme}://{url.netloc.split("@")[1]}'
27+
else:
28+
user = None
29+
password = None
30+
_host= f'{url.scheme}://{url.netloc}'
31+
return user, password, _host
32+
33+
def power_set(host, port, index, value):
34+
# curl -u admin:1234 -v -X PUT -H "X-CSRF: x" --data 'value=true' --digest http://192.168.0.100/restapi/relay/outlets/=0/state/
35+
# curl -u admin:1234 -v -X PUT -H "X-CSRF: x" --data 'value=false' --digest http://192.168.0.100/restapi/relay/outlets/=0/state/
36+
# curl --insecure -u admin:1234 -v -X PUT -H "X-CSRF: x" --data 'value=true' --digest https://192.168.0.100/restapi/relay/outlets/=0/state/
37+
# curl --insecure -u admin:1234 -v -X PUT -H "X-CSRF: x" --data 'value=false' --digest https://192.168.0.100/restapi/relay/outlets/=0/state/
38+
assert port is None
39+
40+
index = int(index)
41+
value = 'true' if value else 'false'
42+
payload = {'value' : value }
43+
headers = {'X-CSRF': 'x', 'Accept': 'application/json'}
44+
user, password, url = extract_user_password_from_host(host)
45+
host = f'{url}/restapi/relay/outlets/={index}/state/'
46+
with urllib3.warnings.catch_warnings():
47+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
48+
if user and password:
49+
r = requests.put(host, data=payload, auth=HTTPDigestAuth(user, password), headers=headers, verify=False)
50+
else:
51+
r = requests.put(host, data=payload, headers=headers, verify=False)
52+
r.raise_for_status()
53+
54+
def power_get(host, port, index):
55+
# curl -u admin:1234 -v -X GET -H "X-CSRF: x" --digest http://192.168.0.100/restapi/relay/outlets/=0/state/
56+
# curl --insecure -u admin:1234 -v -X GET -H "X-CSRF: x" --digest https://192.168.0.100/restapi/relay/outlets/=0/state/
57+
assert port is None
58+
59+
index = int(index)
60+
user, password, url = extract_user_password_from_host(host)
61+
headers = {'X-CSRF': 'x', 'Accept': 'application/json'}
62+
host = f'{url}/restapi/relay/outlets/={index}/state/'
63+
with urllib3.warnings.catch_warnings():
64+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
65+
if user and password:
66+
r = requests.get(host, auth=HTTPDigestAuth(user, password), headers=headers, verify=False)
67+
else:
68+
r = requests.get(host, headers=headers, verify=False)
69+
r.raise_for_status()
70+
statuses = r.json()
71+
return statuses[0]

tests/test_powerdriver.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ def test_import_backends(self):
279279
import labgrid.driver.power.apc
280280
import labgrid.driver.power.digipower
281281
import labgrid.driver.power.digitalloggers_http
282+
import labgrid.driver.power.digitalloggers_restapi
282283
import labgrid.driver.power.eth008
283284
import labgrid.driver.power.gude
284285
import labgrid.driver.power.gude24

0 commit comments

Comments
 (0)