diff --git a/hcloud/floating_ips/client.py b/hcloud/floating_ips/client.py index 9e76eee5..00ea7d49 100644 --- a/hcloud/floating_ips/client.py +++ b/hcloud/floating_ips/client.py @@ -10,7 +10,7 @@ class BoundFloatingIP(BoundModelBase): model = FloatingIP - def __init__(self, client, data): + def __init__(self, client, data, complete=True): from hcloud.servers.client import BoundServer server = data.get("server") if server is not None: @@ -20,7 +20,7 @@ def __init__(self, client, data): if home_location is not None: data['home_location'] = BoundLocation(client._client.locations, home_location) - super(BoundFloatingIP, self).__init__(client, data) + super(BoundFloatingIP, self).__init__(client, data, complete) def get_actions_list(self, sort=None, page=None, per_page=None): # type: (Optional[List[str]], Optional[int], Optional[int]) -> PageResult[BoundAction, Meta] diff --git a/hcloud/servers/client.py b/hcloud/servers/client.py index 57051a4d..bf483239 100644 --- a/hcloud/servers/client.py +++ b/hcloud/servers/client.py @@ -3,8 +3,9 @@ from hcloud.actions.client import BoundAction from hcloud.core.domain import add_meta_to_result +from hcloud.floating_ips.client import BoundFloatingIP from hcloud.isos.client import BoundIso -from hcloud.servers.domain import Server, CreateServerResponse, ResetPasswordResponse, EnableRescueResponse, RequestConsoleResponse +from hcloud.servers.domain import Server, CreateServerResponse, ResetPasswordResponse, EnableRescueResponse, RequestConsoleResponse, PublicNetwork, IPv4Address, IPv6Network from hcloud.volumes.client import BoundVolume from hcloud.images.domain import CreateImageResponse from hcloud.images.client import BoundImage @@ -15,7 +16,7 @@ class BoundServer(BoundModelBase): model = Server - def __init__(self, client, data, complete=False): + def __init__(self, client, data, complete=True): datacenter = data.get('datacenter') if datacenter is not None: @@ -38,6 +39,13 @@ def __init__(self, client, data, complete=False): if server_type is not None: data['server_type'] = BoundServerType(client._client.server_types, server_type) + public_net = data.get("public_net") + if public_net: + ipv4_address = IPv4Address(**public_net['ipv4']) + ipv6_network = IPv6Network(**public_net['ipv6']) + floating_ips = [BoundFloatingIP(client._client.floating_ips, {"id": floating_ip}, complete=False) for floating_ip in public_net['floating_ips']] + data['public_net'] = PublicNetwork(ipv4=ipv4_address, ipv6=ipv6_network, floating_ips=floating_ips) + super(BoundServer, self).__init__(client, data, complete) def get_actions_list(self, status=None, sort=None, page=None, per_page=None): diff --git a/hcloud/servers/domain.py b/hcloud/servers/domain.py index bffe4859..1aedaccc 100644 --- a/hcloud/servers/domain.py +++ b/hcloud/servers/domain.py @@ -28,25 +28,25 @@ class Server(BaseDomain): created = ISODateTime() def __init__( - self, - id, - name=None, - status=None, - created=None, - public_net=None, - server_type=None, - datacenter=None, - image=None, - iso=None, - rescue_enabled=None, - locked=None, - backup_window=None, - outgoing_traffic=None, - ingoing_traffic=None, - included_traffic=None, - protection=None, - labels=None, - volumes=None, + self, + id, + name=None, + status=None, + created=None, + public_net=None, + server_type=None, + datacenter=None, + image=None, + iso=None, + rescue_enabled=None, + locked=None, + backup_window=None, + outgoing_traffic=None, + ingoing_traffic=None, + included_traffic=None, + protection=None, + labels=None, + volumes=None, ): self.id = id self.name = name @@ -78,10 +78,10 @@ class CreateServerResponse(BaseDomain): def __init__( self, - server, # type: BoundServer - action, # type: BoundAction - next_actions, # type: List[Action] - root_password # type: str + server, # type: BoundServer + action, # type: BoundAction + next_actions, # type: List[Action] + root_password # type: str ): self.server = server self.action = action @@ -97,8 +97,8 @@ class ResetPasswordResponse(BaseDomain): def __init__( self, - action, # type: BoundAction - root_password # type: str + action, # type: BoundAction + root_password # type: str ): self.action = action self.root_password = root_password @@ -112,8 +112,8 @@ class EnableRescueResponse(BaseDomain): def __init__( self, - action, # type: BoundAction - root_password # type: str + action, # type: BoundAction + root_password # type: str ): self.action = action self.root_password = root_password @@ -128,10 +128,66 @@ class RequestConsoleResponse(BaseDomain): def __init__( self, - action, # type: BoundAction - wss_url, # type: str - password, # type: str + action, # type: BoundAction + wss_url, # type: str + password, # type: str ): self.action = action self.wss_url = wss_url self.password = password + + +class PublicNetwork(BaseDomain): + __slots__ = ( + "ipv4", + "ipv6", + "floating_ips" + ) + + def __init__(self, + ipv4, # type: IPv4Address + ipv6, # type: IPv6Network + floating_ips, # type: List[BoundFloatingIP] + ): + self.ipv4 = ipv4 + self.ipv6 = ipv6 + self.floating_ips = floating_ips + + +class IPv4Address(BaseDomain): + __slots__ = ( + "ip", + "blocked", + "dns_ptr" + ) + + def __init__(self, + ip, # type: str + blocked, # type: bool + dns_ptr, # type: str + ): + self.ip = ip + self.blocked = blocked + self.dns_ptr = dns_ptr + + +class IPv6Network(BaseDomain): + __slots__ = ( + "ip", + "blocked", + "dns_ptr", + "network", + "network_mask" + ) + + def __init__(self, + ip, # type: str + blocked, # type: bool + dns_ptr, # type: list + ): + self.ip = ip + self.blocked = blocked + self.dns_ptr = dns_ptr + ip_parts = self.ip.split("/") # 2001:db8::/64 to 2001:db8:: and 64 + self.network = ip_parts[0] + self.network_mask = ip_parts[1] diff --git a/tests/unit/servers/conftest.py b/tests/unit/servers/conftest.py index a25699b1..898f07fe 100644 --- a/tests/unit/servers/conftest.py +++ b/tests/unit/servers/conftest.py @@ -9,7 +9,26 @@ def response_simple_server(): "name": "my-server", "status": "running", "created": "2016-01-30T23:50+00:00", - "public_net": {}, + "public_net": { + "ipv4": { + "ip": "1.2.3.4", + "blocked": False, + "dns_ptr": "server01.example.com" + }, + "ipv6": { + "ip": "2001:db8::/64", + "blocked": False, + "dns_ptr": [ + { + "ip": "2001:db8::1", + "dns_ptr": "server.example.com" + } + ] + }, + "floating_ips": [ + 478 + ] + }, "server_type": { "id": 1, "name": "cx11", @@ -110,7 +129,25 @@ def response_create_simple_server(): "name": "my-server", "status": "running", "created": "2016-01-30T23:50+00:00", - "public_net": {}, + "public_net": { + "ipv4": { + "ip": "1.2.3.4", + "blocked": False, + "dns_ptr": "server01.example.com" + }, + "ipv6": { + "ip": "2001:db8::/64", + "blocked": False, + "dns_ptr": [ + { + "ip": "2001:db8::1", + "dns_ptr": "server.example.com" + } + ] + }, + "floating_ips": [ + ] + }, "server_type": { "id": 1, "name": "cx11", @@ -380,7 +417,26 @@ def response_simple_servers(): "name": "my-server", "status": "running", "created": "2016-01-30T23:50+00:00", - "public_net": {}, + "public_net": { + "ipv4": { + "ip": "1.2.3.4", + "blocked": False, + "dns_ptr": "server01.example.com" + }, + "ipv6": { + "ip": "2001:db8::/64", + "blocked": False, + "dns_ptr": [ + { + "ip": "2001:db8::1", + "dns_ptr": "server.example.com" + } + ] + }, + "floating_ips": [ + 478 + ] + }, "server_type": { "id": 1, "name": "cx11", @@ -474,7 +530,26 @@ def response_simple_servers(): "name": "my-server2", "status": "running", "created": "2016-03-30T23:50+00:00", - "public_net": {}, + "public_net": { + "ipv4": { + "ip": "1.2.3.4", + "blocked": False, + "dns_ptr": "server01.example.com" + }, + "ipv6": { + "ip": "2001:db8::/64", + "blocked": False, + "dns_ptr": [ + { + "ip": "2001:db8::1", + "dns_ptr": "server.example.com" + } + ] + }, + "floating_ips": [ + 478 + ] + }, "server_type": { "id": 1, "name": "cx11", diff --git a/tests/unit/servers/test_client.py b/tests/unit/servers/test_client.py index cd8f0876..dd31c071 100644 --- a/tests/unit/servers/test_client.py +++ b/tests/unit/servers/test_client.py @@ -1,10 +1,11 @@ import mock import pytest +from hcloud.floating_ips.client import BoundFloatingIP from hcloud.isos.client import BoundIso from hcloud.servers.client import ServersClient, BoundServer -from hcloud.servers.domain import Server +from hcloud.servers.domain import Server, PublicNetwork, IPv4Address, IPv6Network from hcloud.volumes.client import BoundVolume from hcloud.volumes.domain import Volume from hcloud.images.domain import Image @@ -32,7 +33,21 @@ def test_bound_server_init(self, response_full_server): assert bound_server.id == 42 assert bound_server.name == "my-server" - assert bound_server.public_net["floating_ips"] == [478] + assert isinstance(bound_server.public_net, PublicNetwork) + assert isinstance(bound_server.public_net.ipv4, IPv4Address) + assert bound_server.public_net.ipv4.ip == "1.2.3.4" + assert bound_server.public_net.ipv4.blocked is False + assert bound_server.public_net.ipv4.dns_ptr == "server01.example.com" + + assert isinstance(bound_server.public_net.ipv6, IPv6Network) + assert bound_server.public_net.ipv6.ip == "2001:db8::/64" + assert bound_server.public_net.ipv6.blocked is False + assert bound_server.public_net.ipv6.network == "2001:db8::" + assert bound_server.public_net.ipv6.network_mask == "64" + + assert isinstance(bound_server.public_net.floating_ips[0], BoundFloatingIP) + assert bound_server.public_net.floating_ips[0].id == 478 + assert bound_server.public_net.floating_ips[0].complete is False assert isinstance(bound_server.datacenter, BoundDatacenter) assert bound_server.datacenter._client == bound_server._client._client.datacenters