Skip to content

Commit cf1838f

Browse files
awaelchlipre-commit-ci[bot]
authored andcommitted
Expose public and private IP in LightningWork (#17742)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent f2f187f commit cf1838f

File tree

9 files changed

+54
-18
lines changed

9 files changed

+54
-18
lines changed

src/lightning/app/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
77

88
## [UnReleased] - 2023-04-DD
99

10+
- Added the property `LightningWork.public_ip` that exposes the public IP of the `LightningWork` instance ([#17742](https://github.com/Lightning-AI/lightning/pull/17742))
11+
12+
1013
### Changed
1114

1215
-
1316

1417

1518
### Fixed
1619

17-
-
20+
- Fixed `LightningWork.internal_ip` that was mistakenly exposing the public IP instead; now exposes the private/internal IP address ([#17742](https://github.com/Lightning-AI/lightning/pull/17742))
1821

1922

2023
## [2.0.2] - 2023-04-24

src/lightning/app/components/database/server.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,10 @@ def db_url(self) -> Optional[str]:
231231
use_localhost = "LIGHTNING_APP_STATE_URL" not in os.environ
232232
if use_localhost:
233233
return self.url
234-
if self.internal_ip != "":
235-
return f"http://{self.internal_ip}:{self.port}"
236-
return self.internal_ip
234+
ip_addr = self.public_ip or self.internal_ip
235+
if ip_addr != "":
236+
return f"http://{ip_addr}:{self.port}"
237+
return ip_addr
237238

238239
def on_exit(self):
239240
self._exit_event.set()

src/lightning/app/components/serve/auto_scaler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ def __init__(
180180
raise ValueError("cold_start_proxy must be of type ColdStartProxy or str")
181181

182182
def get_internal_url(self) -> str:
183-
if not self._internal_ip:
184-
raise ValueError("Internal IP not set")
185-
return f"http://{self._internal_ip}:{self._port}"
183+
if not self._public_ip:
184+
raise ValueError("Public IP not set")
185+
return f"http://{self._public_ip}:{self._port}"
186186

187187
async def send_batch(self, batch: List[Tuple[str, _BatchRequestModel]], server_url: str):
188188
request_data: List[_LoadBalancer._input_type] = [b[1] for b in batch]
@@ -386,7 +386,7 @@ def update_servers(self, server_works: List[LightningWork]):
386386
"""
387387
old_server_urls = set(self.servers)
388388
current_server_urls = {
389-
f"http://{server._internal_ip}:{server.port}" for server in server_works if server._internal_ip
389+
f"http://{server._public_ip}:{server.port}" for server in server_works if server._internal_ip
390390
}
391391

392392
# doing nothing if no server work has been added/removed

src/lightning/app/core/work.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class LightningWork:
6060
"_url",
6161
"_restarting",
6262
"_internal_ip",
63+
"_public_ip",
6364
)
6465

6566
_run_executor_cls: Type[WorkRunExecutor] = WorkRunExecutor
@@ -138,6 +139,7 @@ def __init__(
138139
"_url",
139140
"_future_url",
140141
"_internal_ip",
142+
"_public_ip",
141143
"_restarting",
142144
"_cloud_compute",
143145
"_display_name",
@@ -148,6 +150,7 @@ def __init__(
148150
self._url: str = ""
149151
self._future_url: str = "" # The cache URL is meant to defer resolving the url values.
150152
self._internal_ip: str = ""
153+
self._public_ip: str = ""
151154
# setattr_replacement is used by the multiprocessing runtime to send the latest changes to the main coordinator
152155
self._setattr_replacement: Optional[Callable[[str, Any], None]] = None
153156
self._name: str = ""
@@ -212,6 +215,15 @@ def internal_ip(self) -> str:
212215
"""
213216
return self._internal_ip
214217

218+
@property
219+
def public_ip(self) -> str:
220+
"""The public ip address of this LightningWork, reachable from the internet.
221+
222+
By default, this attribute returns the empty string and the ip address will only be returned once the work runs.
223+
Locally, this address is undefined (empty string) and in the cloud it will be determined by the cluster.
224+
"""
225+
return self._public_ip
226+
215227
def _on_init_end(self) -> None:
216228
self._local_build_config.on_work_init(self)
217229
self._cloud_build_config.on_work_init(self, self._cloud_compute)

src/lightning/app/utilities/proxies.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,8 @@ def run_once(self):
494494
# Set this here after the state observer is initialized, since it needs to record it as a change and send
495495
# it back to the flow
496496
default_internal_ip = "127.0.0.1" if constants.LIGHTNING_CLOUDSPACE_HOST is None else "0.0.0.0" # noqa: S104
497-
self.work._internal_ip = os.environ.get("LIGHTNING_NODE_IP", default_internal_ip)
497+
self.work._internal_ip = os.environ.get("LIGHTNING_NODE_PRIVATE_IP", default_internal_ip)
498+
self.work._public_ip = os.environ.get("LIGHTNING_NODE_IP", "")
498499

499500
# 8. Patch the setattr method of the work. This needs to be done after step 4, so we don't
500501
# send delta while calling `set_state`.

tests/tests_app/core/test_lightning_app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def test_simple_app(tmpdir):
119119
"_url": "",
120120
"_future_url": "",
121121
"_internal_ip": "",
122+
"_public_ip": "",
122123
"_paths": {},
123124
"_port": None,
124125
"_restarting": False,
@@ -136,6 +137,7 @@ def test_simple_app(tmpdir):
136137
"_url": "",
137138
"_future_url": "",
138139
"_internal_ip": "",
140+
"_public_ip": "",
139141
"_paths": {},
140142
"_port": None,
141143
"_restarting": False,
@@ -982,7 +984,7 @@ def run(self):
982984
def test_state_size_constant_growth():
983985
app = LightningApp(SizeFlow())
984986
MultiProcessRuntime(app, start_server=False).dispatch()
985-
assert app.root._state_sizes[0] <= 7965
987+
assert app.root._state_sizes[0] <= 8304
986988
assert app.root._state_sizes[20] <= 26550
987989

988990

tests/tests_app/core/test_lightning_flow.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ def run(self):
324324
"_paths": {},
325325
"_restarting": False,
326326
"_internal_ip": "",
327+
"_public_ip": "",
327328
"_display_name": "",
328329
"_cloud_compute": {
329330
"type": "__cloud_compute__",
@@ -349,6 +350,7 @@ def run(self):
349350
"_paths": {},
350351
"_restarting": False,
351352
"_internal_ip": "",
353+
"_public_ip": "",
352354
"_display_name": "",
353355
"_cloud_compute": {
354356
"type": "__cloud_compute__",
@@ -388,6 +390,7 @@ def run(self):
388390
"_paths": {},
389391
"_restarting": False,
390392
"_internal_ip": "",
393+
"_public_ip": "",
391394
"_display_name": "",
392395
"_cloud_compute": {
393396
"type": "__cloud_compute__",
@@ -413,6 +416,7 @@ def run(self):
413416
"_paths": {},
414417
"_restarting": False,
415418
"_internal_ip": "",
419+
"_public_ip": "",
416420
"_display_name": "",
417421
"_cloud_compute": {
418422
"type": "__cloud_compute__",

tests/tests_app/structures/test_structures.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def run(self):
4646
"_restarting": False,
4747
"_display_name": "",
4848
"_internal_ip": "",
49+
"_public_ip": "",
4950
"_cloud_compute": {
5051
"type": "__cloud_compute__",
5152
"name": "cpu-small",
@@ -80,6 +81,7 @@ def run(self):
8081
"_restarting": False,
8182
"_display_name": "",
8283
"_internal_ip": "",
84+
"_public_ip": "",
8385
"_cloud_compute": {
8486
"type": "__cloud_compute__",
8587
"name": "cpu-small",
@@ -114,6 +116,7 @@ def run(self):
114116
"_restarting": False,
115117
"_display_name": "",
116118
"_internal_ip": "",
119+
"_public_ip": "",
117120
"_cloud_compute": {
118121
"type": "__cloud_compute__",
119122
"name": "cpu-small",
@@ -199,6 +202,7 @@ def run(self):
199202
"_paths": {},
200203
"_restarting": False,
201204
"_internal_ip": "",
205+
"_public_ip": "",
202206
"_display_name": "",
203207
"_cloud_compute": {
204208
"type": "__cloud_compute__",
@@ -233,6 +237,7 @@ def run(self):
233237
"_paths": {},
234238
"_restarting": False,
235239
"_internal_ip": "",
240+
"_public_ip": "",
236241
"_display_name": "",
237242
"_cloud_compute": {
238243
"type": "__cloud_compute__",
@@ -262,6 +267,7 @@ def run(self):
262267
"_paths": {},
263268
"_restarting": False,
264269
"_internal_ip": "",
270+
"_public_ip": "",
265271
"_display_name": "",
266272
"_cloud_compute": {
267273
"type": "__cloud_compute__",

tests/tests_app/utilities/test_proxies.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -641,16 +641,21 @@ def test_state_observer():
641641

642642

643643
@pytest.mark.parametrize(
644-
("patch_constants", "environment", "expected_ip_addr"),
644+
("patch_constants", "environment", "expected_public_ip", "expected_private_ip"),
645645
[
646-
({}, {}, "127.0.0.1"),
647-
({"LIGHTNING_CLOUDSPACE_HOST": "any"}, {}, "0.0.0.0"), # noqa: S104
648-
({}, {"LIGHTNING_NODE_IP": "10.10.10.5"}, "10.10.10.5"),
646+
({}, {}, "", "127.0.0.1"),
647+
({"LIGHTNING_CLOUDSPACE_HOST": "any"}, {}, "", "0.0.0.0"), # noqa: S104
648+
(
649+
{},
650+
{"LIGHTNING_NODE_IP": "85.44.2.25", "LIGHTNING_NODE_PRIVATE_IP": "10.10.10.5"},
651+
"85.44.2.25",
652+
"10.10.10.5",
653+
),
649654
],
650655
indirect=["patch_constants"],
651656
)
652-
def test_work_runner_sets_internal_ip(patch_constants, environment, expected_ip_addr):
653-
"""Test that the WorkRunner updates the internal ip address as soon as the Work starts running."""
657+
def test_work_runner_sets_public_and_private_ip(patch_constants, environment, expected_public_ip, expected_private_ip):
658+
"""Test that the WorkRunner updates the public and private address as soon as the Work starts running."""
654659

655660
class Work(LightningWork):
656661
def run(self):
@@ -690,11 +695,13 @@ def run(self):
690695

691696
with mock.patch.dict(os.environ, environment, clear=True):
692697
work_runner.setup()
693-
# The internal ip address only becomes available once the hardware is up / the work is running.
698+
# The public ip address only becomes available once the hardware is up / the work is running.
699+
assert work.public_ip == ""
694700
assert work.internal_ip == ""
695701
with contextlib.suppress(Empty):
696702
work_runner.run_once()
697-
assert work.internal_ip == expected_ip_addr
703+
assert work.public_ip == expected_public_ip
704+
assert work.internal_ip == expected_private_ip
698705

699706

700707
class WorkBi(LightningWork):

0 commit comments

Comments
 (0)