hysn-firecracker-python 1.0.5__tar.gz → 1.0.6__tar.gz
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.
- {hysn_firecracker_python-1.0.5/hysn_firecracker_python.egg-info → hysn_firecracker_python-1.0.6}/PKG-INFO +1 -1
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/_version.py +3 -3
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/network.py +87 -39
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/utils.py +14 -1
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6/hysn_firecracker_python.egg-info}/PKG-INFO +1 -1
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_port_forward.py +67 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_utils.py +48 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/.github/workflows/pypi-release.yml +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/.gitignore +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/AGENTS.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/Dockerfile.test +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/FIRECRACKER_SETUP.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/LICENSE +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/Makefile +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/QUICKSTART.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/README.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/TODO.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/assets/img/firecracker.png +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/assets/rootfs/setup-firecracker-official.sh +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/cleanup_firecracker.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/debian/compat +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/debian/control +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/debian/copyright +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/debian/rules +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docker-compose.test.yml +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/README.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/api-reference.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/cleanup.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/configuration.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/examples.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/getting-started.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/index.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/network.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/docs/testing-in-docker.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/Dockerfile +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/configure_vm_network.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/create_vm.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/create_vm_with_filesystem_format.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/id_rsa +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/id_rsa.pub +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/init +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/load_snapshot.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/sample.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/setup.sh +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/__init__.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/api.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/config.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/exceptions.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/logger.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/microvm.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/process.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/scripts.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/firecracker/vmm.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/hysn_firecracker_python.egg-info/SOURCES.txt +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/hysn_firecracker_python.egg-info/dependency_links.txt +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/hysn_firecracker_python.egg-info/entry_points.txt +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/hysn_firecracker_python.egg-info/requires.txt +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/hysn_firecracker_python.egg-info/top_level.txt +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/pyproject.toml +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/requirements.txt +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/scripts/cleanup_resources.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/scripts/run-tests-docker.sh +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/setup.cfg +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/setup.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/README.md +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/conftest.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_api_client.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_cleanup.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_docker_integration.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_error_handling.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_logger.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_microvm.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_microvm_error_paths.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_microvm_initialization.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_network_error_paths.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_networking.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_process_manager.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_rootfs_format.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_scripts.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_snapshots.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_vm_configuration.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_vmm_manager.py +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/uv.lock +0 -0
- {hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/verify-setup.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 0,
|
|
21
|
+
__version__ = version = '1.0.6'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 6)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g3b21589ba'
|
|
@@ -497,6 +497,18 @@ class NetworkManager:
|
|
|
497
497
|
has_correct_dnat = False
|
|
498
498
|
|
|
499
499
|
for e in expr:
|
|
500
|
+
# Current form: `fib daddr type local` (no host-IP match).
|
|
501
|
+
if (
|
|
502
|
+
"match" in e
|
|
503
|
+
and e["match"]["op"] == "=="
|
|
504
|
+
and "fib" in e["match"].get("left", {})
|
|
505
|
+
and "daddr"
|
|
506
|
+
in e["match"]["left"]["fib"].get("flags", [])
|
|
507
|
+
and e["match"]["right"] == "local"
|
|
508
|
+
):
|
|
509
|
+
has_daddr_match = True
|
|
510
|
+
|
|
511
|
+
# Legacy form: exact `ip daddr <host_ip>` payload match.
|
|
500
512
|
if (
|
|
501
513
|
"match" in e
|
|
502
514
|
and e["match"]["op"] == "=="
|
|
@@ -684,6 +696,71 @@ class NetworkManager:
|
|
|
684
696
|
)
|
|
685
697
|
return False
|
|
686
698
|
|
|
699
|
+
def _build_prerouting_rule(
|
|
700
|
+
self,
|
|
701
|
+
id: str,
|
|
702
|
+
family: str,
|
|
703
|
+
host_port: int,
|
|
704
|
+
dest_ip: str,
|
|
705
|
+
dest_port: int,
|
|
706
|
+
protocol: str = "tcp",
|
|
707
|
+
):
|
|
708
|
+
"""Build the PREROUTING DNAT rule for a port forward.
|
|
709
|
+
|
|
710
|
+
The destination-address match uses ``fib daddr type local`` instead of a
|
|
711
|
+
single detected host IP. This matches any address the host owns, on every
|
|
712
|
+
provider, with zero host-IP detection -- fixing the ``ip daddr 0.0.0.0``
|
|
713
|
+
bug where a failed/empty public-IP lookup produced a rule that never fired.
|
|
714
|
+
|
|
715
|
+
Args:
|
|
716
|
+
id (str): Machine ID, used in the rule comment.
|
|
717
|
+
family (str): nftables family ("ip" or "ip6").
|
|
718
|
+
host_port (int): Host port to forward.
|
|
719
|
+
dest_ip (str): IP address to forward to.
|
|
720
|
+
dest_port (int): Port to forward to.
|
|
721
|
+
protocol (str): Protocol to forward (default: "tcp").
|
|
722
|
+
|
|
723
|
+
Returns:
|
|
724
|
+
dict: An nftables ``add`` rule object for the PREROUTING chain.
|
|
725
|
+
"""
|
|
726
|
+
return {
|
|
727
|
+
"add": {
|
|
728
|
+
"rule": {
|
|
729
|
+
"family": family,
|
|
730
|
+
"table": "nat",
|
|
731
|
+
"chain": "PREROUTING",
|
|
732
|
+
"comment": f"machine_id={id} host_port={host_port} vm_port={dest_port}",
|
|
733
|
+
"expr": [
|
|
734
|
+
{
|
|
735
|
+
"match": {
|
|
736
|
+
"op": "==",
|
|
737
|
+
"left": {
|
|
738
|
+
"fib": {
|
|
739
|
+
"result": "type",
|
|
740
|
+
"flags": ["daddr"],
|
|
741
|
+
}
|
|
742
|
+
},
|
|
743
|
+
"right": "local",
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
"match": {
|
|
748
|
+
"op": "==",
|
|
749
|
+
"left": {
|
|
750
|
+
"payload": {
|
|
751
|
+
"protocol": protocol,
|
|
752
|
+
"field": "dport",
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
"right": host_port,
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
{"dnat": {"addr": dest_ip, "port": dest_port}},
|
|
759
|
+
],
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
687
764
|
def add_port_forward(
|
|
688
765
|
self,
|
|
689
766
|
id: str,
|
|
@@ -695,8 +772,13 @@ class NetworkManager:
|
|
|
695
772
|
):
|
|
696
773
|
"""Port forward a port to a new IP and port.
|
|
697
774
|
|
|
775
|
+
The PREROUTING rule matches ``fib daddr type local`` (any address the host
|
|
776
|
+
owns), so ``host_ip`` is used only to detect the IP family (IPv4 vs IPv6);
|
|
777
|
+
its value no longer appears in the rule match. This avoids the
|
|
778
|
+
``ip daddr 0.0.0.0`` bug on hosts where public-IP detection fails.
|
|
779
|
+
|
|
698
780
|
Args:
|
|
699
|
-
host_ip (str): IP address to
|
|
781
|
+
host_ip (str): IP address used only to detect IPv4/IPv6 family.
|
|
700
782
|
host_port (int): Port to forward.
|
|
701
783
|
dest_ip (str): IP address to forward to.
|
|
702
784
|
dest_port (int): Port to forward to.
|
|
@@ -767,45 +849,11 @@ class NetworkManager:
|
|
|
767
849
|
}
|
|
768
850
|
)
|
|
769
851
|
|
|
770
|
-
# Add PREROUTING rule
|
|
852
|
+
# Add PREROUTING rule (fib daddr type local -- no host-IP detection)
|
|
771
853
|
rules["nftables"].append(
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
"family": family,
|
|
776
|
-
"table": "nat",
|
|
777
|
-
"chain": "PREROUTING",
|
|
778
|
-
"comment": f"machine_id={id} host_port={host_port} vm_port={dest_port}",
|
|
779
|
-
"expr": [
|
|
780
|
-
{
|
|
781
|
-
"match": {
|
|
782
|
-
"op": "==",
|
|
783
|
-
"left": {
|
|
784
|
-
"payload": {
|
|
785
|
-
"protocol": family,
|
|
786
|
-
"field": "daddr",
|
|
787
|
-
}
|
|
788
|
-
},
|
|
789
|
-
"right": host_ip,
|
|
790
|
-
}
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
"match": {
|
|
794
|
-
"op": "==",
|
|
795
|
-
"left": {
|
|
796
|
-
"payload": {
|
|
797
|
-
"protocol": protocol,
|
|
798
|
-
"field": "dport",
|
|
799
|
-
}
|
|
800
|
-
},
|
|
801
|
-
"right": host_port,
|
|
802
|
-
}
|
|
803
|
-
},
|
|
804
|
-
{"dnat": {"addr": dest_ip, "port": dest_port}},
|
|
805
|
-
],
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
}
|
|
854
|
+
self._build_prerouting_rule(
|
|
855
|
+
id, family, host_port, dest_ip, dest_port, protocol
|
|
856
|
+
)
|
|
809
857
|
)
|
|
810
858
|
|
|
811
859
|
# Only add POSTROUTING rule if it doesn't already exist
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import random
|
|
3
3
|
import string
|
|
4
4
|
import signal
|
|
5
|
+
import ipaddress
|
|
5
6
|
import requests
|
|
6
7
|
import subprocess
|
|
7
8
|
import socket
|
|
@@ -185,8 +186,20 @@ def get_public_ip(timeout: int = 5):
|
|
|
185
186
|
|
|
186
187
|
for url in URLS:
|
|
187
188
|
try:
|
|
188
|
-
|
|
189
|
+
ip = _try_get_ip_from_url(url, timeout)
|
|
189
190
|
except requests.RequestException:
|
|
190
191
|
continue
|
|
191
192
|
|
|
193
|
+
# Reject empty/garbage and unspecified (0.0.0.0 / ::) responses so a bad
|
|
194
|
+
# service can never silently produce a dead "daddr 0.0.0.0" forward rule.
|
|
195
|
+
try:
|
|
196
|
+
ip_obj = ipaddress.ip_address(ip)
|
|
197
|
+
except ValueError:
|
|
198
|
+
continue
|
|
199
|
+
|
|
200
|
+
if ip_obj.is_unspecified:
|
|
201
|
+
continue
|
|
202
|
+
|
|
203
|
+
return str(ip_obj)
|
|
204
|
+
|
|
192
205
|
raise RuntimeError("Failed to get public IP")
|
|
@@ -2,10 +2,77 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
from unittest.mock import patch
|
|
5
6
|
|
|
6
7
|
import pytest
|
|
7
8
|
|
|
8
9
|
from firecracker import MicroVM
|
|
10
|
+
from firecracker.network import NetworkManager
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestPreroutingRuleBuild:
|
|
14
|
+
"""Unit tests for the PREROUTING DNAT rule builder (no nftables/KVM needed).
|
|
15
|
+
|
|
16
|
+
Guards the `ip daddr 0.0.0.0` regression: the rule must match
|
|
17
|
+
`fib daddr type local`, never an exact host-IP daddr payload.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def _build(self, **kwargs):
|
|
21
|
+
with patch("firecracker.network.IPRoute"):
|
|
22
|
+
nm = NetworkManager()
|
|
23
|
+
defaults = dict(
|
|
24
|
+
id="9fngkuf7",
|
|
25
|
+
family="ip",
|
|
26
|
+
host_port=37699,
|
|
27
|
+
dest_ip="172.115.48.209",
|
|
28
|
+
dest_port=22,
|
|
29
|
+
protocol="tcp",
|
|
30
|
+
)
|
|
31
|
+
defaults.update(kwargs)
|
|
32
|
+
return nm._build_prerouting_rule(**defaults)
|
|
33
|
+
|
|
34
|
+
def test_uses_fib_daddr_type_local(self):
|
|
35
|
+
"""Rule matches any local address via fib, not a single host IP."""
|
|
36
|
+
expr = self._build()["add"]["rule"]["expr"]
|
|
37
|
+
fib_matches = [
|
|
38
|
+
e
|
|
39
|
+
for e in expr
|
|
40
|
+
if "match" in e and "fib" in e["match"].get("left", {})
|
|
41
|
+
]
|
|
42
|
+
assert len(fib_matches) == 1
|
|
43
|
+
m = fib_matches[0]["match"]
|
|
44
|
+
assert m["op"] == "=="
|
|
45
|
+
assert m["left"]["fib"]["result"] == "type"
|
|
46
|
+
assert "daddr" in m["left"]["fib"]["flags"]
|
|
47
|
+
assert m["right"] == "local"
|
|
48
|
+
|
|
49
|
+
def test_no_exact_daddr_payload_match(self):
|
|
50
|
+
"""Regression: no `ip daddr <addr>` payload match remains in the rule."""
|
|
51
|
+
expr = self._build()["add"]["rule"]["expr"]
|
|
52
|
+
for e in expr:
|
|
53
|
+
left = e.get("match", {}).get("left", {})
|
|
54
|
+
if "payload" in left:
|
|
55
|
+
assert left["payload"]["field"] != "daddr"
|
|
56
|
+
|
|
57
|
+
def test_dport_and_dnat_preserved(self):
|
|
58
|
+
"""dport match and dnat target unchanged."""
|
|
59
|
+
expr = self._build()["add"]["rule"]["expr"]
|
|
60
|
+
dport = next(
|
|
61
|
+
e["match"]
|
|
62
|
+
for e in expr
|
|
63
|
+
if "match" in e
|
|
64
|
+
and e["match"]["left"].get("payload", {}).get("field") == "dport"
|
|
65
|
+
)
|
|
66
|
+
assert dport["right"] == 37699
|
|
67
|
+
dnat = next(e["dnat"] for e in expr if "dnat" in e)
|
|
68
|
+
assert dnat == {"addr": "172.115.48.209", "port": 22}
|
|
69
|
+
|
|
70
|
+
def test_comment_format_unchanged(self):
|
|
71
|
+
"""Comment key is unchanged -- deletion/idempotency paths depend on it."""
|
|
72
|
+
rule = self._build()["add"]["rule"]
|
|
73
|
+
assert rule["comment"] == "machine_id=9fngkuf7 host_port=37699 vm_port=22"
|
|
74
|
+
assert rule["chain"] == "PREROUTING"
|
|
75
|
+
assert rule["table"] == "nat"
|
|
9
76
|
|
|
10
77
|
KERNEL_FILE = "/var/lib/firecracker/vmlinux-6.1.159"
|
|
11
78
|
BASE_ROOTFS = "/var/lib/firecracker/devsecops-box.img"
|
|
@@ -167,3 +167,51 @@ class TestUtilsFunctions:
|
|
|
167
167
|
|
|
168
168
|
with pytest.raises(RuntimeError, match="VMM ID required"):
|
|
169
169
|
test_func(None)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class TestGetPublicIP:
|
|
173
|
+
"""Tests for get_public_ip validation (never yield 0.0.0.0/empty)."""
|
|
174
|
+
|
|
175
|
+
def test_returns_valid_ip(self):
|
|
176
|
+
"""A valid IP from the first service is returned."""
|
|
177
|
+
from unittest.mock import patch
|
|
178
|
+
from firecracker.utils import get_public_ip
|
|
179
|
+
|
|
180
|
+
with patch(
|
|
181
|
+
"firecracker.utils._try_get_ip_from_url", return_value="138.201.226.62"
|
|
182
|
+
):
|
|
183
|
+
assert get_public_ip() == "138.201.226.62"
|
|
184
|
+
|
|
185
|
+
def test_skips_unspecified_then_returns_valid(self):
|
|
186
|
+
"""0.0.0.0 from one service is skipped; next valid IP wins."""
|
|
187
|
+
from unittest.mock import patch
|
|
188
|
+
from firecracker.utils import get_public_ip
|
|
189
|
+
|
|
190
|
+
with patch(
|
|
191
|
+
"firecracker.utils._try_get_ip_from_url",
|
|
192
|
+
side_effect=["0.0.0.0", "203.0.113.5", "203.0.113.9"],
|
|
193
|
+
):
|
|
194
|
+
assert get_public_ip() == "203.0.113.5"
|
|
195
|
+
|
|
196
|
+
def test_skips_empty_and_garbage(self):
|
|
197
|
+
"""Empty/garbage responses are skipped, not returned."""
|
|
198
|
+
from unittest.mock import patch
|
|
199
|
+
from firecracker.utils import get_public_ip
|
|
200
|
+
|
|
201
|
+
with patch(
|
|
202
|
+
"firecracker.utils._try_get_ip_from_url",
|
|
203
|
+
side_effect=["", "not-an-ip", "203.0.113.7"],
|
|
204
|
+
):
|
|
205
|
+
assert get_public_ip() == "203.0.113.7"
|
|
206
|
+
|
|
207
|
+
def test_raises_when_all_unspecified_or_invalid(self):
|
|
208
|
+
"""All services returning 0.0.0.0/garbage -> RuntimeError, never 0.0.0.0."""
|
|
209
|
+
from unittest.mock import patch
|
|
210
|
+
from firecracker.utils import get_public_ip
|
|
211
|
+
|
|
212
|
+
with patch(
|
|
213
|
+
"firecracker.utils._try_get_ip_from_url",
|
|
214
|
+
side_effect=["0.0.0.0", "", "::"],
|
|
215
|
+
):
|
|
216
|
+
with pytest.raises(RuntimeError, match="Failed to get public IP"):
|
|
217
|
+
get_public_ip()
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/.github/ISSUE_TEMPLATE/bug_report.md
RENAMED
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/.github/workflows/pypi-release.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/examples/configure_vm_network.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/scripts/cleanup_resources.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_docker_integration.py
RENAMED
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_error_handling.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_microvm_error_paths.py
RENAMED
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_microvm_initialization.py
RENAMED
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_network_error_paths.py
RENAMED
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_process_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hysn_firecracker_python-1.0.5 → hysn_firecracker_python-1.0.6}/tests/test_vm_configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|