Skip to content

Commit 4f04551

Browse files
Add ability to pass credentials to InfluxDB publisher client (#432)
* Add passing credentials via env var or file * Add passing credentials to docs
1 parent e722873 commit 4f04551

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed

docs/agents/influxdb_publisher.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,40 @@ Add the InfluxDB Publisher Agent container to your docker compose file::
4646
hostname: ocs-docker
4747
environment:
4848
- INSTANCE_ID=influxagent
49+
- INFLUXDB_USERNAME=admin # optional
50+
- INFLUXDB_PASSWORD=password # optional
4951
volumes:
5052
- ${OCS_CONFIG_DIR}:/config:ro
5153

54+
By default, InfluxDB HTTP authentication is not required. However, if needed,
55+
you can optionally pass credentials to use when connecting to your InfluxDB
56+
instance through the environment variables shown above or through a file, for
57+
instance if you would like to use Docker Secrets. A Docker Secrets example is
58+
shown below::
59+
60+
secrets:
61+
INFLUXDB_USERNAME:
62+
file: ${PWD}/secrets/INFLUXDB_USERNAME
63+
INFLUXDB_PASSWORD:
64+
file: ${PWD}/secrets/INFLUXDB_PASSWORD
65+
services:
66+
ocs-influxdb-publisher:
67+
image: simonsobs/ocs:latest
68+
hostname: ocs-docker
69+
secrets:
70+
- INFLUXDB_USERNAME
71+
- INFLUXDB_PASSWORD
72+
environment:
73+
- INSTANCE_ID=influxagent
74+
- INFLUXDB_USERNAME_FILE=/run/secrets/INFLUXDB_USERNAME
75+
- INFLUXDB_PASSWORD_FILE=/run/secrets/INFLUXDB_PASSWORD
76+
volumes:
77+
- ${OCS_CONFIG_DIR}:/config:ro
78+
79+
.. note::
80+
The ``INFLUXDB_USERNAME`` and ``INFLUXDB_PASSWORD`` variables will take
81+
precedence if they are also present when using the ``_FILE`` variables.
82+
5283
You will also need an instance of InfluxDB running somewhere on your network.
5384
This likely should go in a separate docker compose file so that it remains
5485
online at all times. An example compose file would look like::

ocs/agents/influxdb_publisher/drivers.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import time
23
import txaio
34

@@ -31,6 +32,39 @@ def timestamp2influxtime(time, protocol):
3132
return influx_t
3233

3334

35+
def _get_credentials():
36+
"""Read credentials from environment variable or file.
37+
38+
Reads from either `INFLUXDB_USERNAME`, `INFLUXDB_PASSWORD`,
39+
`INFLUXDB_USERNAME_FILE`, or `INFLUXDB_PASSWORD_FILE`. Precedence is given
40+
to the non-`_FILE` variables.
41+
42+
Returns:
43+
A tuple of (username, password). Defaults to ('root', 'root') if none
44+
of the environment variables are present.
45+
46+
"""
47+
username_file = os.environ.get('INFLUXDB_USERNAME_FILE')
48+
password_file = os.environ.get('INFLUXDB_PASSWORD_FILE')
49+
50+
username = None
51+
password = None
52+
if username_file is not None:
53+
with open(username_file, 'r', encoding="utf-8") as f:
54+
username = f.read().rstrip('\r\n')
55+
if password_file is not None:
56+
with open(password_file, 'r', encoding="utf-8") as f:
57+
password = f.read().rstrip('\r\n')
58+
59+
username_default = 'root' if username is None else username
60+
password_default = 'root' if password is None else password
61+
62+
username = os.environ.get('INFLUXDB_USERNAME', username_default)
63+
password = os.environ.get('INFLUXDB_PASSWORD', password_default)
64+
65+
return username, password
66+
67+
3468
class Publisher:
3569
"""
3670
Data publisher. This manages data to be published to the InfluxDB.
@@ -81,7 +115,14 @@ def __init__(self, host, database, incoming_data, port=8086, protocol='line',
81115
print(f"gzip encoding enabled: {gzip}")
82116
print(f"data protocol: {protocol}")
83117

84-
self.client = InfluxDBClient(host=self.host, port=self.port, gzip=gzip)
118+
username, password = _get_credentials()
119+
120+
self.client = InfluxDBClient(
121+
host=self.host,
122+
port=self.port,
123+
username=username,
124+
password=password,
125+
gzip=gzip)
85126

86127
db_list = None
87128
# ConnectionError here is indicative of InfluxDB being down
@@ -92,6 +133,12 @@ def __init__(self, host, database, incoming_data, port=8086, protocol='line',
92133
LOG.error("Connection error, attempting to reconnect to DB.")
93134
self.client = InfluxDBClient(host=self.host, port=self.port, gzip=gzip)
94135
time.sleep(1)
136+
except InfluxDBClientError as err:
137+
if err.code == 401:
138+
LOG.error("Failed to authenticate. Check your credentials.")
139+
else:
140+
LOG.error(f"Unknown client error: {err}")
141+
time.sleep(1)
95142
if operate_callback and not operate_callback():
96143
break
97144

tests/test_influxdb_publisher.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import os
2+
13
import pytest
24

3-
from ocs.agents.influxdb_publisher.drivers import Publisher, timestamp2influxtime
5+
from ocs.agents.influxdb_publisher.drivers import Publisher, timestamp2influxtime, _get_credentials
46

57

68
@pytest.mark.parametrize("t,protocol,expected",
@@ -27,3 +29,32 @@ def test_format_data():
2729

2830
expected = 'test_address,feed=test_feed key1=1i,key2=2.3,key3="test" 1615394417359038720'
2931
assert Publisher.format_data(data, feed, 'line')[0] == expected
32+
33+
34+
def test__get_credentials(tmp_path):
35+
# Defaults
36+
assert _get_credentials() == ('root', 'root')
37+
38+
# Set from file
39+
d = tmp_path
40+
username_file = d / "username"
41+
username_file.write_text("admin", encoding="utf-8")
42+
password_file = d / "password"
43+
password_file.write_text("testpass", encoding="utf-8")
44+
45+
os.environ['INFLUXDB_USERNAME_FILE'] = str(username_file)
46+
os.environ['INFLUXDB_PASSWORD_FILE'] = str(password_file)
47+
assert _get_credentials() == ('admin', 'testpass')
48+
49+
# Set from env var
50+
os.environ['INFLUXDB_USERNAME'] = 'user_var'
51+
os.environ['INFLUXDB_PASSWORD'] = 'pass_var'
52+
assert _get_credentials() == ('user_var', 'pass_var')
53+
54+
# Cleanup
55+
vars_ = ['INFLUXDB_USERNAME_FILE',
56+
'INFLUXDB_PASSWORD_FILE',
57+
'INFLUXDB_USERNAME',
58+
'INFLUXDB_PASSWORD']
59+
for v in vars_:
60+
os.environ.pop(v)

0 commit comments

Comments
 (0)