Skip to content

Commit d3aae57

Browse files
Separate IP address observer into separate script (#581)
Before, ip_addresss_observer.py simultaneously served two different functions, one to provide imports used in charm.py and one to call charm.py itself (via juju-run). Now, those two functions are separated. Fixes issue where ops import causes `juju-run` script to fail because ops is not available from /usr/bin/python3 when using a full virtual environment (needed for charmcraft 3 poetry plugin migration)—now `juju-run` script does not import ops since it never needed it Context: https://chat.canonical.com/canonical/pl/drhbrt84y3yc7xwc5431a1o5de
1 parent 928cd42 commit d3aae57

File tree

3 files changed

+63
-53
lines changed

3 files changed

+63
-53
lines changed

charmcraft.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ parts:
1919
- -requirements.txt
2020
prime:
2121
- snap_revisions.json
22+
- scripts
23+
- templates
2224
charm:
2325
build-snaps:
2426
- rustup

scripts/ip_address_dispatcher.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright 2023 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
"""Dispatch event if IP address changes."""
5+
6+
import subprocess
7+
import logging
8+
import socket
9+
import sys
10+
import time
11+
12+
logger = logging.getLogger(__name__)
13+
14+
def dispatch(run_command, unit, charm_directory):
15+
"""Use the juju-run command to dispatch :class:`IPAddressChangeEvent`."""
16+
dispatch_sub_command = "JUJU_DISPATCH_PATH=hooks/ip_address_change {}/dispatch"
17+
subprocess.run([run_command, "-u", unit, dispatch_sub_command.format(charm_directory)])
18+
19+
20+
def main():
21+
"""Main watch and dispatch loop.
22+
23+
Determine the host IP address every 30 seconds, and dispatch and event if it
24+
changes.
25+
"""
26+
run_command, unit, charm_directory = sys.argv[1:]
27+
28+
def _get_local_ip():
29+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
30+
s.settimeout(0)
31+
32+
try:
33+
s.connect(("10.10.10.10", 1))
34+
ip = s.getsockname()[0]
35+
except Exception:
36+
logger.exception("Unable to get local IP address")
37+
ip = "127.0.0.1"
38+
39+
return ip
40+
41+
previous_ip_address = None
42+
while True:
43+
ip_address = _get_local_ip()
44+
45+
if not previous_ip_address:
46+
print(f"Setting initial ip address to {ip_address}")
47+
sys.stdout.flush()
48+
previous_ip_address = ip_address
49+
elif ip_address != previous_ip_address:
50+
print(f"Detected ip address change from {previous_ip_address} to {ip_address}")
51+
sys.stdout.flush()
52+
previous_ip_address = ip_address
53+
dispatch(run_command, unit, charm_directory)
54+
55+
time.sleep(30)
56+
57+
58+
if __name__ == "__main__":
59+
main()

src/ip_address_observer.py

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
# Copyright 2023 Canonical Ltd.
22
# See LICENSE file for licensing details.
33

4-
"""IP address changes observer."""
4+
"""Set up IP address changes observer."""
55

66
import logging
77
import os
88
import signal
9-
import socket
109
import subprocess
11-
import sys
12-
import time
1310
import typing
1411

1512
from ops.charm import CharmEvents
@@ -74,7 +71,7 @@ def start_observer(self):
7471
process = subprocess.Popen(
7572
[
7673
"/usr/bin/python3",
77-
"src/ip_address_observer.py",
74+
"scripts/ip_address_dispatcher.py",
7875
juju_command,
7976
self.charm.unit.name,
8077
self.charm.charm_dir,
@@ -110,51 +107,3 @@ def check_pid(pid: int) -> bool:
110107
return False
111108
else:
112109
return True
113-
114-
115-
def dispatch(run_command, unit, charm_directory):
116-
"""Use the juju-run command to dispatch :class:`IPAddressChangeEvent`."""
117-
dispatch_sub_command = "JUJU_DISPATCH_PATH=hooks/ip_address_change {}/dispatch"
118-
subprocess.run([run_command, "-u", unit, dispatch_sub_command.format(charm_directory)])
119-
120-
121-
def main():
122-
"""Main watch and dispatch loop.
123-
124-
Determine the host IP address every 30 seconds, and dispatch and event if it
125-
changes.
126-
"""
127-
run_command, unit, charm_directory = sys.argv[1:]
128-
129-
def _get_local_ip():
130-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
131-
s.settimeout(0)
132-
133-
try:
134-
s.connect(("10.10.10.10", 1))
135-
ip = s.getsockname()[0]
136-
except Exception:
137-
logger.exception("Unable to get local IP address")
138-
ip = "127.0.0.1"
139-
140-
return ip
141-
142-
previous_ip_address = None
143-
while True:
144-
ip_address = _get_local_ip()
145-
146-
if not previous_ip_address:
147-
print(f"Setting initial ip address to {ip_address}")
148-
sys.stdout.flush()
149-
previous_ip_address = ip_address
150-
elif ip_address != previous_ip_address:
151-
print(f"Detected ip address change from {previous_ip_address} to {ip_address}")
152-
sys.stdout.flush()
153-
previous_ip_address = ip_address
154-
dispatch(run_command, unit, charm_directory)
155-
156-
time.sleep(30)
157-
158-
159-
if __name__ == "__main__":
160-
main()

0 commit comments

Comments
 (0)