Skip to content

Commit 09b3dcd

Browse files
lukasmetznerjooola
andauthored
feat(primary-ip): assignee_type behavior changed when creating a primary ip (#647)
In the create Primary IP call, the `assignee_type` argument is now only send when the `assignee_id` argument is set. The `assignee_type` argument will stop defaulting to 'server' in the near future, consider explicitly setting this argument when needed. #### Primary IPs `assignee_type` behavior change As of 1 August 2026, the behavior of the Primary IP `assignee_type` property will change, and will return `unassigned` when the Primary IP is not assigned (when `assignee_id` is `null`). The goal is to eventually assign Primary IPs to other resource types, not only to `server`. See the [changelog](https://docs.hetzner.cloud/changelog#2026-04-27-primary-ips-will-return-unassigned) for more details. In addition, the Primary IP request body `assignee_type` property of the operation [`POST /v1/primary_ips`](https://docs.hetzner.cloud/reference/cloud#tag/primary-ips/create_primary_ip) is now optional. Primary IPs created without `assignee_type` return `server` until 1 August 2026, after this date, its value will be `unassigned`. See the [changelog](https://docs.hetzner.cloud/changelog#2026-04-27-primary-ips-make-assignee_type-optional) for more details. Co-authored-by: jo <ljonas@riseup.net>
1 parent b309d97 commit 09b3dcd

2 files changed

Lines changed: 48 additions & 6 deletions

File tree

hcloud/primary_ips/client.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def create(
311311
name: str,
312312
datacenter: Datacenter | BoundDatacenter | None = None,
313313
location: Location | BoundLocation | None = None,
314-
assignee_type: str | None = "server",
314+
assignee_type: str | None = None,
315315
assignee_id: int | None = None,
316316
auto_delete: bool | None = False,
317317
labels: dict[str, str] | None = None,
@@ -328,13 +328,12 @@ def create(
328328
:param labels: Dict[str, str] (optional) User-defined labels (key-value pairs)
329329
:return: :class:`CreatePrimaryIPResponse <hcloud.primary_ips.domain.CreatePrimaryIPResponse>`
330330
"""
331-
332331
data: dict[str, Any] = {
333332
"name": name,
334333
"type": type,
335-
"assignee_type": assignee_type,
336334
"auto_delete": auto_delete,
337335
}
336+
338337
if datacenter is not None:
339338
warnings.warn(
340339
"The 'datacenter' argument is deprecated and will be removed after 1 July 2026. "
@@ -348,10 +347,24 @@ def create(
348347
data["location"] = location.id_or_name
349348
if assignee_id is not None:
350349
data["assignee_id"] = assignee_id
350+
if assignee_type is None:
351+
assignee_type = "server"
352+
warnings.warn(
353+
"The 'assignee_type' argument will no longer default to 'server' "
354+
"and will be required together with the 'assignee_id' argument. "
355+
"Please explicitly set the 'assignee_type' argument.",
356+
DeprecationWarning,
357+
stacklevel=2,
358+
)
359+
data["assignee_type"] = assignee_type
351360
if labels is not None:
352361
data["labels"] = labels
353362

354-
response = self._client.request(url=self._base_url, json=data, method="POST")
363+
response = self._client.request(
364+
method="POST",
365+
url=self._base_url,
366+
json=data,
367+
)
355368

356369
action = None
357370
if response.get("action") is not None:

tests/unit/primary_ips/test_client.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ def test_create_with_location(
162162
json={
163163
"name": "primary-ip1",
164164
"type": "ipv4",
165-
"assignee_type": "server",
166165
"location": "fsn1",
167166
"auto_delete": False,
168167
},
@@ -194,7 +193,6 @@ def test_create_with_datacenter(
194193
json={
195194
"name": "primary-ip1",
196195
"type": "ipv4",
197-
"assignee_type": "server",
198196
"datacenter": "fsn1-dc14",
199197
"auto_delete": False,
200198
},
@@ -236,6 +234,37 @@ def test_create_with_assignee_id(
236234
assert_bound_primary_ip1(result.primary_ip, resource_client)
237235
assert_bound_action1(result.action, resource_client._parent.actions)
238236

237+
def test_create_with_assignee_type_deprecation(
238+
self,
239+
request_mock: mock.MagicMock,
240+
resource_client: PrimaryIPsClient,
241+
primary_ip1,
242+
action1_running,
243+
):
244+
request_mock.return_value = {
245+
"primary_ip": primary_ip1,
246+
"action": action1_running,
247+
}
248+
249+
with pytest.deprecated_call():
250+
resource_client.create(
251+
type="ipv4",
252+
name="primary-ip1",
253+
assignee_id=17,
254+
)
255+
256+
request_mock.assert_called_with(
257+
method="POST",
258+
url="/primary_ips",
259+
json={
260+
"name": "primary-ip1",
261+
"type": "ipv4",
262+
"assignee_id": 17,
263+
"assignee_type": "server",
264+
"auto_delete": False,
265+
},
266+
)
267+
239268
@pytest.mark.parametrize(
240269
"primary_ip",
241270
[

0 commit comments

Comments
 (0)