Skip to content

Commit b3e6cb9

Browse files
authored
Merge pull request #143 from hetznercloud/placement-groups
Placement groups
2 parents a8a19de + 4ece164 commit b3e6cb9

14 files changed

Lines changed: 757 additions & 1 deletion

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
PlacementGroupsClient
2+
==================
3+
4+
5+
.. autoclass:: hcloud.placement_groups.client.PlacementGroupsClient
6+
:members:
7+
8+
.. autoclass:: hcloud.placement_groups.client.BoundPlacementGroup
9+
:members:
10+
11+
.. autoclass:: hcloud.placement_groups.domain.PlacementGroup
12+
:members:
13+
14+
.. autoclass:: hcloud.placement_groups.domain.CreatePlacementGroupResponse
15+
:members:

hcloud/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = "1.14.1"
1+
VERSION = "1.15.0"

hcloud/hcloud.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from hcloud.datacenters.client import DatacentersClient
1919
from hcloud.load_balancers.client import LoadBalancersClient
2020
from hcloud.load_balancer_types.client import LoadBalancerTypesClient
21+
from hcloud.placement_groups.client import PlacementGroupsClient
2122

2223
from .__version__ import VERSION
2324
from .firewalls.client import FirewallsClient
@@ -149,6 +150,12 @@ def __init__(
149150
:type: :class:`FirewallsClient <hcloud.firewalls.client.FirewallsClient>`
150151
"""
151152

153+
self.placement_groups = PlacementGroupsClient(self)
154+
"""PlacementGroupsClient Instance
155+
156+
:type: :class:`PlacementGroupsClient <hcloud.placement_groups.client.PlacementGroupsClient>`
157+
"""
158+
152159
def _get_user_agent(self):
153160
"""Get the user agent of the hcloud-python instance with the user application name (if specified)
154161
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# -*- coding: utf-8 -*-

hcloud/placement_groups/client.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# -*- coding: utf-8 -*-
2+
from hcloud.actions.client import BoundAction
3+
from hcloud.core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
4+
5+
from hcloud.placement_groups.domain import PlacementGroup, CreatePlacementGroupResponse
6+
7+
8+
class BoundPlacementGroup(BoundModelBase):
9+
model = PlacementGroup
10+
11+
def update(self, labels=None, name=None):
12+
# type: (Optional[str], Optional[Dict[str, str]], Optional[str]) -> BoundPlacementGroup
13+
"""Updates the name or labels of a Placement Group
14+
15+
:param labels: Dict[str, str] (optional)
16+
User-defined labels (key-value pairs)
17+
:param name: str, (optional)
18+
New Name to set
19+
:return: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
20+
"""
21+
return self._client.update(self, labels, name)
22+
23+
def delete(self):
24+
# type: () -> bool
25+
"""Deletes a Placement Group
26+
27+
:return: boolean
28+
"""
29+
return self._client.delete(self)
30+
31+
32+
class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
33+
results_list_attribute_name = "placement_groups"
34+
35+
def get_by_id(self, id):
36+
# type: (int) -> BoundPlacementGroup
37+
"""Returns a specific Placement Group object
38+
39+
:param id: int
40+
:return: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
41+
"""
42+
response = self._client.request(
43+
url="/placement_groups/{placement_group_id}".format(placement_group_id=id),
44+
method="GET",
45+
)
46+
return BoundPlacementGroup(self, response["placement_group"])
47+
48+
def get_list(
49+
self,
50+
label_selector=None, # type: Optional[str]
51+
page=None, # type: Optional[int]
52+
per_page=None, # type: Optional[int]
53+
name=None, # type: Optional[str]
54+
sort=None, # type: Optional[List[str]]
55+
type=None, # type: Optional[str]
56+
):
57+
# type: (...) -> PageResults[List[BoundPlacementGroup]]
58+
"""Get a list of Placement Groups
59+
60+
:param label_selector: str (optional)
61+
Can be used to filter Placement Groups by labels. The response will only contain Placement Groups matching the label selector values.
62+
:param page: int (optional)
63+
Specifies the page to fetch
64+
:param per_page: int (optional)
65+
Specifies how many results are returned by page
66+
:param name: str (optional)
67+
Can be used to filter Placement Groups by their name.
68+
:param sort: List[str] (optional)
69+
Choices: id name created (You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default))
70+
:return: (List[:class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`], :class:`Meta <hcloud.core.domain.Meta>`)
71+
"""
72+
73+
params = {}
74+
75+
if label_selector is not None:
76+
params["label_selector"] = label_selector
77+
if page is not None:
78+
params["page"] = page
79+
if per_page is not None:
80+
params["per_page"] = per_page
81+
if name is not None:
82+
params["name"] = name
83+
if sort is not None:
84+
params["sort"] = sort
85+
if type is not None:
86+
params["type"] = type
87+
response = self._client.request(
88+
url="/placement_groups", method="GET", params=params
89+
)
90+
placement_groups = [
91+
BoundPlacementGroup(self, placement_group_data)
92+
for placement_group_data in response["placement_groups"]
93+
]
94+
95+
return self._add_meta_to_result(placement_groups, response)
96+
97+
def get_all(self, label_selector=None, name=None, sort=None):
98+
# type: (Optional[str], Optional[str], Optional[List[str]]) -> List[BoundPlacementGroup]
99+
"""Get all Placement Groups
100+
101+
:param label_selector: str (optional)
102+
Can be used to filter Placement Groups by labels. The response will only contain Placement Groups matching the label selector values.
103+
:param name: str (optional)
104+
Can be used to filter Placement Groups by their name.
105+
:param sort: List[str] (optional)
106+
Choices: id name created (You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default))
107+
:return: List[:class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`]
108+
"""
109+
return super(PlacementGroupsClient, self).get_all(
110+
label_selector=label_selector, name=name, sort=sort
111+
)
112+
113+
def get_by_name(self, name):
114+
# type: (str) -> BoundPlacementGroup
115+
"""Get Placement Group by name
116+
117+
:param name: str
118+
Used to get Placement Group by name
119+
:return: class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
120+
"""
121+
return super(PlacementGroupsClient, self).get_by_name(name)
122+
123+
def create(
124+
self,
125+
name, # type: str
126+
type, # type: str
127+
labels=None, # type: Optional[Dict[str, str]]
128+
):
129+
# type: (...) -> CreatePlacementGroupResponse
130+
"""Creates a new Placement Group.
131+
132+
:param name: str
133+
Placement Group Name
134+
:param type: str
135+
Type of the Placement Group
136+
:param labels: Dict[str, str] (optional)
137+
User-defined labels (key-value pairs)
138+
139+
:return: :class:`CreatePlacementGroupResponse <hcloud.placement_groups.domain.CreatePlacementGroupResponse>`
140+
"""
141+
data = {"name": name, "type": type}
142+
if labels is not None:
143+
data["labels"] = labels
144+
response = self._client.request(
145+
url="/placement_groups", json=data, method="POST"
146+
)
147+
148+
action = None
149+
if response.get("action") is not None:
150+
action = BoundAction(self._client.action, response["action"])
151+
152+
result = CreatePlacementGroupResponse(
153+
placement_group=BoundPlacementGroup(self, response["placement_group"]),
154+
action=action,
155+
)
156+
return result
157+
158+
def update(self, placement_group, labels=None, name=None):
159+
# type: (PlacementGroup, Optional[Dict[str, str]], Optional[str]) -> BoundPlacementGroup
160+
"""Updates the description or labels of a Placement Group.
161+
162+
:param placement_group: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>` or :class:`PlacementGroup <hcloud.placement_groups.domain.PlacementGroup>`
163+
:param labels: Dict[str, str] (optional)
164+
User-defined labels (key-value pairs)
165+
:param name: str (optional)
166+
New name to set
167+
:return: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
168+
"""
169+
170+
data = {}
171+
if labels is not None:
172+
data["labels"] = labels
173+
if name is not None:
174+
data["name"] = name
175+
176+
response = self._client.request(
177+
url="/placement_groups/{placement_group_id}".format(
178+
placement_group_id=placement_group.id
179+
),
180+
method="PUT",
181+
json=data,
182+
)
183+
return BoundPlacementGroup(self, response["placement_group"])
184+
185+
def delete(self, placement_group):
186+
# type: (PlacementGroup) -> bool
187+
"""Deletes a Placement Group.
188+
189+
:param placement_group: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>` or :class:`PlacementGroup <hcloud.placement_groups.domain.PlacementGroup>`
190+
:return: boolean
191+
"""
192+
self._client.request(
193+
url="/placement_groups/{placement_group_id}".format(
194+
placement_group_id=placement_group.id
195+
),
196+
method="DELETE",
197+
)
198+
return True

hcloud/placement_groups/domain.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
from dateutil.parser import isoparse
3+
4+
from hcloud.core.domain import BaseDomain
5+
6+
7+
class PlacementGroup(BaseDomain):
8+
"""Placement Group Domain
9+
10+
:param id: int
11+
ID of the Placement Group
12+
:param name: str
13+
Name of the Placement Group
14+
:param labels: dict
15+
User-defined labels (key-value pairs)
16+
:param servers: List[ int ]
17+
List of server IDs assigned to the Placement Group
18+
:param type: str
19+
Type of the Placement Group
20+
:param created: datetime
21+
Point in time when the image was created
22+
"""
23+
24+
__slots__ = ("id", "name", "labels", "servers", "type", "created")
25+
26+
"""Placement Group type spread
27+
spreads all servers in the group on different vhosts
28+
"""
29+
TYPE_SPREAD = "spread"
30+
31+
def __init__(
32+
self, id=None, name=None, labels=None, servers=None, type=None, created=None
33+
):
34+
self.id = id
35+
self.name = name
36+
self.labels = labels
37+
self.servers = servers
38+
self.type = type
39+
self.created = isoparse(created) if created else None
40+
41+
42+
class CreatePlacementGroupResponse(BaseDomain):
43+
"""Create Placement Group Response Domain
44+
45+
:param placement_group: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
46+
The Placement Group which was created
47+
:param action: :class:`BoundAction <hcloud.actions.client.BoundAction>`
48+
The Action which shows the progress of the Placement Group Creation
49+
"""
50+
51+
__slots__ = ("placement_group", "action")
52+
53+
def __init__(
54+
self,
55+
placement_group, # type: BoundPlacementGroup
56+
action, # type: BoundAction
57+
):
58+
self.placement_group = placement_group
59+
self.action = action

0 commit comments

Comments
 (0)