diff --git a/hcloud/firewalls/client.py b/hcloud/firewalls/client.py index a1bd86a..ef26429 100644 --- a/hcloud/firewalls/client.py +++ b/hcloud/firewalls/client.py @@ -3,7 +3,8 @@ from hcloud.core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin from hcloud.core.domain import add_meta_to_result -from hcloud.firewalls.domain import Firewall, CreateFirewallResponse, FirewallRule, FirewallResource +from hcloud.firewalls.domain import Firewall, CreateFirewallResponse, FirewallRule, FirewallResource, \ + FirewallResourceLabelSelector class BoundFirewall(BoundModelBase): @@ -22,9 +23,11 @@ def __init__(self, client, data, complete=True): from hcloud.servers.client import BoundServer ats = [] for a in applied_to: - if a["type"] == "server": + if a["type"] == FirewallResource.TYPE_SERVER: ats.append(FirewallResource(type=a["type"], server=BoundServer(client._client.servers, a["server"], complete=False))) + elif a["type"] == FirewallResource.TYPE_LABEL_SELECTOR: + ats.append(FirewallResource(type=a["type"], label_selector=FirewallResourceLabelSelector(selector=a['label_selector']['selector']))) data['applied_to'] = ats super(BoundFirewall, self).__init__(client, data, complete) diff --git a/hcloud/firewalls/domain.py b/hcloud/firewalls/domain.py index 2a8f147..094e786 100644 --- a/hcloud/firewalls/domain.py +++ b/hcloud/firewalls/domain.py @@ -119,22 +119,30 @@ class FirewallResource: Type of resource referenced :param server: Optional[Server] Server the Firewall is applied to + :param label_selector: Optional[FirewallResourceLabelSelector] + Label Selector for Servers the Firewall should be applied to """ __slots__ = ( "type", "server", + "label_selector" ) TYPE_SERVER = "server" """Firewall Used By Type Server""" + TYPE_LABEL_SELECTOR = "label_selector" + """Firewall Used By Type label_selector""" def __init__( self, type, # type: str server=None, # type: Optional[Server] + label_selector=None, # type: Optional[FirewallResourceLabelSelector] + ): self.type = type self.server = server + self.label_selector = label_selector def to_payload(self): payload = { @@ -142,9 +150,22 @@ def to_payload(self): } if self.server is not None: payload.update({"server": {"id": self.server.id}}) + + if self.label_selector is not None: + payload.update({"label_selector": {"selector": self.label_selector.selector}}) return payload +class FirewallResourceLabelSelector(BaseDomain): + """FirewallResourceLabelSelector Domain + + :param selector: str Target label selector + """ + + def __init__(self, selector=None): + self.selector = selector + + class CreateFirewallResponse(BaseDomain): """Create Firewall Response Domain diff --git a/tests/unit/firewalls/conftest.py b/tests/unit/firewalls/conftest.py index 413f129..88576ce 100644 --- a/tests/unit/firewalls/conftest.py +++ b/tests/unit/firewalls/conftest.py @@ -39,6 +39,12 @@ def response_create_firewall(): "id": 42 }, "type": "server" + }, + { + "type": "label_selector", + "label_selector": { + "selector": "key==value" + } } ] }, @@ -125,6 +131,12 @@ def firewall_response(): "id": 42 }, "type": "server" + }, + { + "type": "label_selector", + "label_selector": { + "selector": "key==value" + } } ] } diff --git a/tests/unit/firewalls/test_client.py b/tests/unit/firewalls/test_client.py index d54f109..1284208 100644 --- a/tests/unit/firewalls/test_client.py +++ b/tests/unit/firewalls/test_client.py @@ -3,7 +3,7 @@ from hcloud.firewalls.client import FirewallsClient, BoundFirewall from hcloud.actions.client import BoundAction -from hcloud.firewalls.domain import Firewall, FirewallRule, FirewallResource +from hcloud.firewalls.domain import Firewall, FirewallRule, FirewallResource, FirewallResourceLabelSelector from hcloud.servers.domain import Server @@ -26,9 +26,11 @@ def test_bound_firewall_init(self, firewall_response): assert len(bound_firewall.rules) == 2 assert isinstance(bound_firewall.applied_to, list) - assert len(bound_firewall.applied_to) == 1 + assert len(bound_firewall.applied_to) == 2 assert bound_firewall.applied_to[0].server.id == 42 assert bound_firewall.applied_to[0].type == "server" + assert bound_firewall.applied_to[1].label_selector.selector == "key==value" + assert bound_firewall.applied_to[1].type == "label_selector" firewall_in_rule = bound_firewall.rules[0] assert isinstance(firewall_in_rule, FirewallRule) @@ -276,7 +278,10 @@ def test_create(self, firewalls_client, response_create_firewall): "Corporate Intranet Protection", rules=[FirewallRule(direction=FirewallRule.DIRECTION_IN, protocol=FirewallRule.PROTOCOL_ICMP, source_ips=["0.0.0.0/0"])], - resources=[FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=4711))] + resources=[ + FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=4711)), + FirewallResource(type=FirewallResource.TYPE_LABEL_SELECTOR, label_selector=FirewallResourceLabelSelector(selector="key==value")) + ] ) firewalls_client._client.request.assert_called_with( url="/firewalls", @@ -298,6 +303,12 @@ def test_create(self, firewalls_client, response_create_firewall): "server": { "id": 4711 } + }, + { + "type": "label_selector", + "label_selector": { + "selector": "key==value" + } } ], } @@ -309,6 +320,7 @@ def test_create(self, firewalls_client, response_create_firewall): assert bound_firewall._client is firewalls_client assert bound_firewall.id == 38 assert bound_firewall.name == "Corporate Intranet Protection" + assert len(bound_firewall.applied_to) == 2 assert len(actions) == 2