portforward 0.6.2__tar.gz → 0.7.1__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.
Potentially problematic release.
This version of portforward might be problematic. Click here for more details.
- {portforward-0.6.2 → portforward-0.7.1}/.github/workflows/release.yml +3 -3
- {portforward-0.6.2 → portforward-0.7.1}/Cargo.lock +2 -2
- {portforward-0.6.2 → portforward-0.7.1}/Cargo.toml +2 -2
- {portforward-0.6.2 → portforward-0.7.1}/HISTORY.rst +9 -0
- {portforward-0.6.2 → portforward-0.7.1}/PKG-INFO +2 -2
- {portforward-0.6.2 → portforward-0.7.1}/README.rst +1 -1
- {portforward-0.6.2 → portforward-0.7.1}/pyproject.toml +2 -2
- {portforward-0.6.2 → portforward-0.7.1}/python/portforward/__init__.py +10 -10
- {portforward-0.6.2 → portforward-0.7.1}/src/portforward.rs +5 -3
- {portforward-0.6.2 → portforward-0.7.1}/tests/test_portforward.py +27 -2
- {portforward-0.6.2 → portforward-0.7.1}/.editorconfig +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/.github/ISSUE_TEMPLATE.md +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/.github/workflows/python-app.yml +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/.gitignore +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/.readthedocs.yml +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/AUTHORS.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/CONTRIBUTING.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/LICENSE +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/Makefile +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/Makefile +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/authors.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/conf.py +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/contributing.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/docs/conf.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/docs/modules.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/history.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/index.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/installation.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/make.bat +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/modules.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/docs/portforward.rst +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/python/portforward/_portforward.pyi +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/python/portforward/py.typed +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/requirements-dev.txt +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/src/lib.rs +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/tests/conftest.py +0 -0
- {portforward-0.6.2 → portforward-0.7.1}/tests/resources.yaml +0 -0
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
strategy:
|
|
22
22
|
matrix:
|
|
23
23
|
target: [x86_64, x86, aarch64]
|
|
24
|
-
version: [ "3.
|
|
24
|
+
version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
25
25
|
steps:
|
|
26
26
|
- uses: actions/checkout@v3
|
|
27
27
|
- uses: actions/setup-python@v4
|
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
strategy:
|
|
46
46
|
matrix:
|
|
47
47
|
target: [x64, x86]
|
|
48
|
-
version: [ "3.
|
|
48
|
+
version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
49
49
|
steps:
|
|
50
50
|
- uses: actions/checkout@v3
|
|
51
51
|
- uses: actions/setup-python@v4
|
|
@@ -69,7 +69,7 @@ jobs:
|
|
|
69
69
|
strategy:
|
|
70
70
|
matrix:
|
|
71
71
|
target: [x86_64, aarch64]
|
|
72
|
-
version: [ "3.
|
|
72
|
+
version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
|
|
73
73
|
steps:
|
|
74
74
|
- uses: actions/checkout@v3
|
|
75
75
|
- uses: actions/setup-python@v4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This file is automatically @generated by Cargo.
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
|
-
version =
|
|
3
|
+
version = 4
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "ahash"
|
|
@@ -1142,7 +1142,7 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
|
|
1142
1142
|
|
|
1143
1143
|
[[package]]
|
|
1144
1144
|
name = "portforward"
|
|
1145
|
-
version = "0.
|
|
1145
|
+
version = "0.7.1"
|
|
1146
1146
|
dependencies = [
|
|
1147
1147
|
"anyhow",
|
|
1148
1148
|
"env_logger",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "portforward"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
@@ -28,7 +28,7 @@ log = "0.4.17"
|
|
|
28
28
|
env_logger = "0.10.0"
|
|
29
29
|
# tokio
|
|
30
30
|
tokio = { version = "1.27.0", features = ["full"] }
|
|
31
|
-
tokio-util = "0.7.
|
|
31
|
+
tokio-util = "0.7.1"
|
|
32
32
|
tokio-stream = { version = "0.1.9", features = ["net"] }
|
|
33
33
|
# k8s
|
|
34
34
|
kube = { version = "^0.81.0", default-features = false, features = ["admission"] }
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
History
|
|
3
3
|
=======
|
|
4
4
|
|
|
5
|
+
0.7.1 (2024-12-15)
|
|
6
|
+
------------------
|
|
7
|
+
* Allow "/" in strings
|
|
8
|
+
* Drop support for Python 3.8
|
|
9
|
+
|
|
10
|
+
0.7.0 (2024-10-18)
|
|
11
|
+
------------------
|
|
12
|
+
* Allow binding to a local random free port
|
|
13
|
+
|
|
5
14
|
0.6.2 (2024-06-19)
|
|
6
15
|
------------------
|
|
7
16
|
* Allow defining binding ip
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: portforward
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -64,11 +64,11 @@ Wheels are available for:
|
|
|
64
64
|
|
|
65
65
|
with Python versions:
|
|
66
66
|
|
|
67
|
-
* 3.8
|
|
68
67
|
* 3.9
|
|
69
68
|
* 3.10
|
|
70
69
|
* 3.11
|
|
71
70
|
* 3.12
|
|
71
|
+
* 3.13
|
|
72
72
|
|
|
73
73
|
**Requirements for installation from source**
|
|
74
74
|
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "portforward"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.1"
|
|
8
8
|
authors = [{ name = "Sebastian Ziemann", email = "corka149@mailbox.org" }]
|
|
9
9
|
description = "Easy Kubernetes Port-Forward For Python"
|
|
10
10
|
readme = "README.rst"
|
|
@@ -34,7 +34,7 @@ module-name = "portforward._portforward"
|
|
|
34
34
|
python-source = "python"
|
|
35
35
|
|
|
36
36
|
[tool.bumpversion]
|
|
37
|
-
current_version = "0.
|
|
37
|
+
current_version = "0.7.1"
|
|
38
38
|
tag = true
|
|
39
39
|
commit = true
|
|
40
40
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Easy Kubernetes Port-Forward For Python
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.
|
|
5
|
+
__version__ = "0.7.1"
|
|
6
6
|
|
|
7
7
|
import asyncio
|
|
8
8
|
import contextlib
|
|
@@ -57,7 +57,7 @@ def forward(
|
|
|
57
57
|
|
|
58
58
|
:param namespace: Target namespace
|
|
59
59
|
:param pod_or_service: Name of target Pod or service
|
|
60
|
-
:param from_port: Local port
|
|
60
|
+
:param from_port: Local port, or 0 to use any free port
|
|
61
61
|
:param to_port: Port inside the pod
|
|
62
62
|
:param config_path: Path for loading kube config
|
|
63
63
|
:param waiting: Delay in seconds
|
|
@@ -129,6 +129,11 @@ class PortForwarder:
|
|
|
129
129
|
def is_stopped(self):
|
|
130
130
|
return self._async_forwarder.is_stopped
|
|
131
131
|
|
|
132
|
+
@property
|
|
133
|
+
def from_port(self):
|
|
134
|
+
"""The local port that was actually used for the portforward."""
|
|
135
|
+
return self._async_forwarder.from_port
|
|
136
|
+
|
|
132
137
|
|
|
133
138
|
class AsyncPortForwarder:
|
|
134
139
|
"""Use the same args as the `portforward.forward` method."""
|
|
@@ -158,11 +163,12 @@ class AsyncPortForwarder:
|
|
|
158
163
|
bind_ip = _validate_ip_address(bind_ip)
|
|
159
164
|
|
|
160
165
|
self.actual_pod_name: str = ""
|
|
166
|
+
self.from_port: int = 0
|
|
161
167
|
self._is_stopped: bool = False
|
|
162
168
|
self.bind_address: str = f"{bind_ip}:{from_port}"
|
|
163
169
|
|
|
164
170
|
async def forward(self):
|
|
165
|
-
self.actual_pod_name = await _portforward.forward(
|
|
171
|
+
(self.actual_pod_name, self.from_port) = await _portforward.forward(
|
|
166
172
|
self.namespace,
|
|
167
173
|
self.pod_or_service,
|
|
168
174
|
self.bind_address,
|
|
@@ -193,14 +199,11 @@ def _validate_str(arg_name, arg) -> str:
|
|
|
193
199
|
if len(arg) == 0:
|
|
194
200
|
raise ValueError(f"{arg_name} cannot be an empty str")
|
|
195
201
|
|
|
196
|
-
if "/" in arg:
|
|
197
|
-
raise ValueError(f"{arg_name} contains illegal character '/'")
|
|
198
|
-
|
|
199
202
|
return arg
|
|
200
203
|
|
|
201
204
|
|
|
202
205
|
def _validate_port(arg_name, arg) -> int:
|
|
203
|
-
in_range = arg and 0
|
|
206
|
+
in_range = arg is not None and 0 <= arg < 65536
|
|
204
207
|
if arg is None or not isinstance(arg, int) or not in_range:
|
|
205
208
|
raise ValueError(f"{arg_name}={arg} is not a valid port")
|
|
206
209
|
|
|
@@ -247,7 +250,4 @@ def _kube_context(context):
|
|
|
247
250
|
if not isinstance(context, str):
|
|
248
251
|
raise ValueError(f"kube_context={context} is not a valid str")
|
|
249
252
|
|
|
250
|
-
if "/" in context:
|
|
251
|
-
raise ValueError("kube_context contains illegal character '/'")
|
|
252
|
-
|
|
253
253
|
return context
|
|
@@ -34,9 +34,10 @@ pub struct ForwardConfig {
|
|
|
34
34
|
kube_context: String,
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/// Creates a connection to a pod. It returns
|
|
37
|
+
/// Creates a connection to a pod. It returns a `(pod_name, from_port)` tuple
|
|
38
|
+
/// with the actual pod name and local port used for the portforward.
|
|
38
39
|
/// It differs from `pod_or_service` when `pod_or_service` represents a service.
|
|
39
|
-
pub async fn forward(config: ForwardConfig) -> anyhow::Result<String> {
|
|
40
|
+
pub async fn forward(config: ForwardConfig) -> anyhow::Result<(String, u16)> {
|
|
40
41
|
debug!("{:?}", config);
|
|
41
42
|
|
|
42
43
|
let client_config = load_config(&config.config_path, &config.kube_context).await?;
|
|
@@ -58,6 +59,7 @@ pub async fn forward(config: ForwardConfig) -> anyhow::Result<String> {
|
|
|
58
59
|
|
|
59
60
|
let addr = SocketAddr::from_str(&config.bind_address).with_context(move || config.bind_address)?;
|
|
60
61
|
let tcp_listener = TcpListener::bind(addr).await?;
|
|
62
|
+
let from_port = tcp_listener.local_addr()?.port();
|
|
61
63
|
let forward_task = setup_forward_task(
|
|
62
64
|
tcp_listener,
|
|
63
65
|
rx,
|
|
@@ -68,7 +70,7 @@ pub async fn forward(config: ForwardConfig) -> anyhow::Result<String> {
|
|
|
68
70
|
|
|
69
71
|
tokio::spawn(forward_task);
|
|
70
72
|
|
|
71
|
-
return Ok(q_name.pod_name);
|
|
73
|
+
return Ok((q_name.pod_name, from_port));
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
async fn load_config(
|
|
@@ -124,18 +124,43 @@ def test_service_portforward_with_success(kind_cluster: KindCluster):
|
|
|
124
124
|
response: requests.Response = requests.get(url_2)
|
|
125
125
|
pytest.fail("Portforward should be closed after leaving the context manager")
|
|
126
126
|
|
|
127
|
+
def test_portforward_from_port_zero_assigns_port(kind_cluster: KindCluster):
|
|
128
|
+
# Arrange
|
|
129
|
+
_create_test_resources(kind_cluster)
|
|
130
|
+
|
|
131
|
+
pod_name = "test-pod"
|
|
132
|
+
config = str(kind_cluster.kubeconfig_path.absolute())
|
|
133
|
+
|
|
134
|
+
local_port = 0 # from port
|
|
135
|
+
pod_port = 3000 # to port
|
|
136
|
+
|
|
137
|
+
pf = portforward.forward(
|
|
138
|
+
TEST_NAMESPACE,
|
|
139
|
+
pod_name,
|
|
140
|
+
local_port,
|
|
141
|
+
pod_port,
|
|
142
|
+
config_path=config,
|
|
143
|
+
kube_context=TEST_CONTEXT,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Act & Assert
|
|
147
|
+
with pf as forwarder:
|
|
148
|
+
assert not forwarder.is_stopped()
|
|
149
|
+
assert forwarder.from_port != 0
|
|
150
|
+
url = f"http://localhost:{forwarder.from_port}/ping"
|
|
151
|
+
response: requests.Response = requests.get(url)
|
|
152
|
+
assert response.status_code == 200
|
|
153
|
+
|
|
127
154
|
|
|
128
155
|
@pytest.mark.parametrize(
|
|
129
156
|
"namespace,pod,from_port,to_port",
|
|
130
157
|
[
|
|
131
158
|
# Namespace
|
|
132
159
|
("", "web", 9000, 80),
|
|
133
|
-
("/test", "web", 9000, 80),
|
|
134
160
|
(1337, "web", 9000, 80),
|
|
135
161
|
(None, "web", 9000, 80),
|
|
136
162
|
# Pod name
|
|
137
163
|
("test", "", 9000, 80),
|
|
138
|
-
("test", "web/", 9000, 80),
|
|
139
164
|
("test", 1337, 9000, 80),
|
|
140
165
|
("test", None, 9000, 80),
|
|
141
166
|
# From port
|
|
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
|