def __init__(self, client, data): from hcloud.servers.client import BoundServer created_from = data.get("created_from") if created_from is not None: data['created_from'] = BoundServer(client._client.servers, created_from, complete=False) bound_to = data.get("bound_to") if bound_to is not None: data['bound_to'] = BoundServer(client._client.servers, {"id": bound_to}, complete=False) super(BoundImage, self).__init__(client, data)
def __init__(self, client, data, complete=True): rules = data.get('rules', []) if rules: rules = [ FirewallRule(direction=rule["direction"], source_ips=rule["source_ips"], destination_ips=rule["destination_ips"], protocol=rule['protocol'], port=rule["port"], description=rule["description"]) for rule in rules ] data['rules'] = rules applied_to = data.get('applied_to', []) if applied_to: from hcloud.servers.client import BoundServer ats = [] for a in applied_to: 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)
def test_bound_server_init(self, response_full_server): bound_server = BoundServer(client=mock.MagicMock(), data=response_full_server['server']) assert bound_server.id == 42 assert bound_server.name == "my-server" 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 assert bound_server.datacenter.id == 1 assert bound_server.datacenter.complete is True assert isinstance(bound_server.server_type, BoundServerType) assert bound_server.server_type._client == bound_server._client._client.server_types assert bound_server.server_type.id == 1 assert bound_server.server_type.complete is True assert len(bound_server.volumes) == 2 assert isinstance(bound_server.volumes[0], BoundVolume) assert bound_server.volumes[ 0]._client == bound_server._client._client.volumes assert bound_server.volumes[0].id == 1 assert bound_server.volumes[0].complete is False assert isinstance(bound_server.volumes[1], BoundVolume) assert bound_server.volumes[ 1]._client == bound_server._client._client.volumes assert bound_server.volumes[1].id == 2 assert bound_server.volumes[1].complete is False assert isinstance(bound_server.image, BoundImage) assert bound_server.image._client == bound_server._client._client.images assert bound_server.image.id == 4711 assert bound_server.image.name == "ubuntu-16.04" assert bound_server.image.complete is True assert isinstance(bound_server.iso, BoundIso) assert bound_server.iso._client == bound_server._client._client.isos assert bound_server.iso.id == 4711 assert bound_server.iso.name == "FreeBSD-11.0-RELEASE-amd64-dvd1" assert bound_server.iso.complete is True
def __init__(self, client, data, complete=True): location = data.get("location") if location is not None: data['location'] = BoundLocation(client._client.locations, location) from hcloud.servers.client import BoundServer server = data.get("server") if server is not None: data['server'] = BoundServer(client._client.servers, {"id": server}, complete=False) super(BoundVolume, self).__init__(client, data, complete)
def __init__(self, client, data, complete=True): from hcloud.servers.client import BoundServer server = data.get("server") if server is not None: data['server'] = BoundServer(client._client.servers, {"id": server}, complete=False) home_location = data.get("home_location") if home_location is not None: data['home_location'] = BoundLocation(client._client.locations, home_location) super(BoundFloatingIP, self).__init__(client, data, complete)
class TestBoundFloatingIPs(object): @pytest.fixture() def bound_floating_ip(self, hetzner_client): return BoundFloatingIP(client=hetzner_client.floating_ips, data=dict(id=4711)) def test_get_actions(self, bound_floating_ip): actions = bound_floating_ip.get_actions() assert len(actions) == 1 assert actions[0].id == 13 assert actions[0].command == "assign_floating_ip" def test_update(self, bound_floating_ip): floating_ip = bound_floating_ip.update(description="New description", labels={}, name="Web Frontend") assert floating_ip.id == 4711 assert floating_ip.description == "New description" assert floating_ip.name == "Web Frontend" def test_delete(self, bound_floating_ip): delete_success = bound_floating_ip.delete() assert delete_success is True @pytest.mark.parametrize( "server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) def test_assign(self, bound_floating_ip, server): action = bound_floating_ip.assign(server) assert action.id == 13 assert action.progress == 0 assert action.command == "assign_floating_ip" def test_unassign(self, bound_floating_ip): action = bound_floating_ip.unassign() assert action.id == 13 assert action.progress == 0 assert action.command == "unassign_floating_ip" def test_change_dns_ptr(self, bound_floating_ip): action = bound_floating_ip.change_dns_ptr("1.2.3.4", "server02.example.com") assert action.id == 13 assert action.progress == 0 assert action.command == "change_dns_ptr"
def __init__(self, client, data, complete=True): subnets = data.get("subnets", []) if subnets is not None: subnets = [NetworkSubnet.from_dict(subnet) for subnet in subnets] data['subnets'] = subnets routes = data.get("routes", []) if routes is not None: routes = [NetworkRoute.from_dict(route) for route in routes] data['routes'] = routes from hcloud.servers.client import BoundServer servers = data.get("servers", []) if servers is not None: servers = [ BoundServer(client._client.servers, {"id": server}, complete=False) for server in servers ] data['servers'] = servers super(BoundNetwork, self).__init__(client, data, complete)
class TestBoundVolume(object): @pytest.fixture() def bound_volume(self, hetzner_client): return BoundVolume(client=hetzner_client.volumes, data=dict(id=4711)) def test_get_actions(self, bound_volume): actions = bound_volume.get_actions() assert len(actions) == 1 assert actions[0].id == 13 assert actions[0].command == "attach_volume" def test_update(self, bound_volume): volume = bound_volume.update(name="new-name", labels={}) assert volume.id == 4711 assert volume.name == "new-name" def test_delete(self, bound_volume): delete_success = bound_volume.delete() assert delete_success is True @pytest.mark.parametrize( "server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) def test_attach(self, hetzner_client, bound_volume, server): action = bound_volume.attach(server) assert action.id == 13 assert action.progress == 0 assert action.command == "attach_volume" def test_detach(self, hetzner_client, bound_volume): action = bound_volume.detach() assert action.id == 13 assert action.progress == 0 assert action.command == "detach_volume" def test_resize(self, hetzner_client, bound_volume): action = bound_volume.resize(50) assert action.id == 13 assert action.progress == 0 assert action.command == "resize_volume"
class TestBoundVolume(object): @pytest.fixture() def bound_volume(self, hetzner_client): return BoundVolume(client=hetzner_client.volumes, data=dict(id=14)) def test_bound_volume_init(self, volume_response): bound_volume = BoundVolume( client=mock.MagicMock(), data=volume_response['volume'] ) assert bound_volume.id == 1 assert bound_volume.created == isoparse("2016-01-30T23:50:11+00:00") assert bound_volume.name == "database-storage" assert isinstance(bound_volume.server, BoundServer) assert bound_volume.server.id == 12 assert bound_volume.size == 42 assert bound_volume.linux_device == "/dev/disk/by-id/scsi-0HC_Volume_4711" assert bound_volume.protection == {"delete": False} assert bound_volume.labels == {} assert bound_volume.status == "available" assert isinstance(bound_volume.location, BoundLocation) assert bound_volume.location.id == 1 assert bound_volume.location.name == "fsn1" assert bound_volume.location.description == "Falkenstein DC Park 1" assert bound_volume.location.country == "DE" assert bound_volume.location.city == "Falkenstein" assert bound_volume.location.latitude == 50.47612 assert bound_volume.location.longitude == 12.370071 def test_get_actions(self, hetzner_client, bound_volume, response_get_actions): hetzner_client.request.return_value = response_get_actions actions = bound_volume.get_actions(sort="id") hetzner_client.request.assert_called_with(url="/volumes/14/actions", method="GET", params={"page": 1, "per_page": 50, "sort": "id"}) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0].id == 13 assert actions[0].command == "attach_volume" def test_update(self, hetzner_client, bound_volume, response_update_volume): hetzner_client.request.return_value = response_update_volume volume = bound_volume.update(name="new-name") hetzner_client.request.assert_called_with(url="/volumes/14", method="PUT", json={"name": "new-name"}) assert volume.id == 4711 assert volume.name == "new-name" def test_delete(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action delete_success = bound_volume.delete() hetzner_client.request.assert_called_with(url="/volumes/14", method="DELETE") assert delete_success is True def test_change_protection(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.change_protection(True) hetzner_client.request.assert_called_with(url="/volumes/14/actions/change_protection", method="POST", json={"delete": True}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize("server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) def test_attach(self, hetzner_client, bound_volume, server, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.attach(server) hetzner_client.request.assert_called_with( url="/volumes/14/actions/attach", method="POST", json={"server": 1} ) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize("server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) def test_attach_with_automount(self, hetzner_client, bound_volume, server, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.attach(server, False) hetzner_client.request.assert_called_with( url="/volumes/14/actions/attach", method="POST", json={"server": 1, "automount": False} ) assert action.id == 1 assert action.progress == 0 def test_detach(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.detach() hetzner_client.request.assert_called_with( url="/volumes/14/actions/detach", method="POST" ) assert action.id == 1 assert action.progress == 0 def test_resize(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.resize(50) hetzner_client.request.assert_called_with( url="/volumes/14/actions/resize", method="POST", json={"size": 50} ) assert action.id == 1 assert action.progress == 0
class TestVolumesClient(object): @pytest.fixture() def volumes_client(self): return VolumesClient(client=mock.MagicMock()) def test_get_by_id(self, volumes_client, volume_response): volumes_client._client.request.return_value = volume_response bound_volume = volumes_client.get_by_id(1) volumes_client._client.request.assert_called_with(url="/volumes/1", method="GET") assert bound_volume._client is volumes_client assert bound_volume.id == 1 assert bound_volume.name == "database-storage" @pytest.mark.parametrize( "params", [ {'label_selector': "label1", 'page': 1, 'per_page': 10}, {} ] ) def test_get_list(self, volumes_client, two_volumes_response, params): volumes_client._client.request.return_value = two_volumes_response result = volumes_client.get_list(**params) volumes_client._client.request.assert_called_with(url="/volumes", method="GET", params=params) bound_volumes = result.volumes assert result.meta is None assert len(bound_volumes) == 2 bound_volume1 = bound_volumes[0] bound_volume2 = bound_volumes[1] assert bound_volume1._client is volumes_client assert bound_volume1.id == 1 assert bound_volume1.name == "database-storage" assert bound_volume2._client is volumes_client assert bound_volume2.id == 2 assert bound_volume2.name == "vault-storage" @pytest.mark.parametrize("params", [{'label_selector': "label1"}]) def test_get_all(self, volumes_client, two_volumes_response, params): volumes_client._client.request.return_value = two_volumes_response bound_volumes = volumes_client.get_all(**params) params.update({'page': 1, 'per_page': 50}) volumes_client._client.request.assert_called_with(url="/volumes", method="GET", params=params) assert len(bound_volumes) == 2 bound_volume1 = bound_volumes[0] bound_volume2 = bound_volumes[1] assert bound_volume1._client is volumes_client assert bound_volume1.id == 1 assert bound_volume1.name == "database-storage" assert bound_volume2._client is volumes_client assert bound_volume2.id == 2 assert bound_volume2.name == "vault-storage" def test_get_by_name(self, volumes_client, one_volumes_response): volumes_client._client.request.return_value = one_volumes_response bound_volume = volumes_client.get_by_name("database-storage") params = {'name': "database-storage"} volumes_client._client.request.assert_called_with(url="/volumes", method="GET", params=params) assert bound_volume._client is volumes_client assert bound_volume.id == 1 assert bound_volume.name == "database-storage" def test_create_with_location(self, volumes_client, volume_create_response): volumes_client._client.request.return_value = volume_create_response response = volumes_client.create( 100, "database-storage", location=Location(name="location"), automount=False, format="xfs" ) volumes_client._client.request.assert_called_with( url="/volumes", method="POST", json={ 'name': "database-storage", 'size': 100, 'location': "location", 'automount': False, 'format': "xfs" } ) bound_volume = response.volume action = response.action next_actions = response.next_actions assert bound_volume._client is volumes_client assert bound_volume.id == 4711 assert bound_volume.name == "database-storage" assert action.id == 13 assert next_actions[0].command == "start_server" @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create_with_server(self, volumes_client, server, volume_create_response): volumes_client._client.request.return_value = volume_create_response volumes_client.create( 100, "database-storage", server=server, automount=False, format="xfs" ) volumes_client._client.request.assert_called_with( url="/volumes", method="POST", json={ 'name': "database-storage", 'size': 100, 'server': 1, 'automount': False, 'format': "xfs" } ) def test_create_negative_size(self, volumes_client): with pytest.raises(ValueError) as e: volumes_client.create( -100, "database-storage", location=Location(name="location") ) assert str(e.value) == "size must be greater than 0" volumes_client._client.request.assert_not_called() @pytest.mark.parametrize("location,server", [(None, None), ("location", Server(id=1))]) def test_create_wrong_location_server_combination(self, volumes_client, location, server): with pytest.raises(ValueError) as e: volumes_client.create( 100, "database-storage", location=location, server=server ) assert str(e.value) == "only one of server or location must be provided" volumes_client._client.request.assert_not_called() @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_get_actions_list(self, volumes_client, volume, response_get_actions): volumes_client._client.request.return_value = response_get_actions result = volumes_client.get_actions_list(volume, sort="id") volumes_client._client.request.assert_called_with(url="/volumes/1/actions", method="GET", params={"sort": "id"}) actions = result.actions assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0]._client == volumes_client._client.actions assert actions[0].id == 13 assert actions[0].command == "attach_volume" @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_update(self, volumes_client, volume, response_update_volume): volumes_client._client.request.return_value = response_update_volume volume = volumes_client.update(volume, name="new-name") volumes_client._client.request.assert_called_with(url="/volumes/1", method="PUT", json={"name": "new-name"}) assert volume.id == 4711 assert volume.name == "new-name" @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_change_protection(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.change_protection(volume, True) volumes_client._client.request.assert_called_with(url="/volumes/1/actions/change_protection", method="POST", json={"delete": True}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_delete(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action delete_success = volumes_client.delete(volume) volumes_client._client.request.assert_called_with(url="/volumes/1", method="DELETE") assert delete_success is True @pytest.mark.parametrize("server,volume", [(Server(id=1), Volume(id=12)), (BoundServer(mock.MagicMock(), dict(id=1)), BoundVolume(mock.MagicMock(), dict(id=12)))]) def test_attach(self, volumes_client, server, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.attach(volume, server) volumes_client._client.request.assert_called_with( url="/volumes/12/actions/attach", method="POST", json={"server": 1} ) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize("volume", [Volume(id=12), BoundVolume(mock.MagicMock(), dict(id=12))]) def test_detach(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.detach(volume) volumes_client._client.request.assert_called_with( url="/volumes/12/actions/detach", method="POST" ) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize("volume", [Volume(id=12), BoundVolume(mock.MagicMock(), dict(id=12))]) def test_resize(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.resize(volume, 50) volumes_client._client.request.assert_called_with( url="/volumes/12/actions/resize", method="POST", json={"size": 50} ) assert action.id == 1 assert action.progress == 0
class TestServersClient(object): def test_get_by_id(self, hetzner_client): server = hetzner_client.servers.get_by_id(42) assert server.id == 42 assert server.volumes == [] assert server.server_type.id == 1 assert server.datacenter.id == 1 assert server.image.id == 4711 def test_get_by_name(self, hetzner_client): server = hetzner_client.servers.get_by_name("my-server") assert server.id == 42 assert server.name == "my-server" assert server.volumes == [] assert server.server_type.id == 1 assert server.datacenter.id == 1 assert server.image.id == 4711 def test_get_list(self, hetzner_client): result = hetzner_client.servers.get_list() servers = result.servers assert servers[0].id == 42 assert servers[0].volumes == [] assert servers[0].server_type.id == 1 assert servers[0].datacenter.id == 1 assert servers[0].image.id == 4711 def test_create(self, hetzner_client): response = hetzner_client.servers.create( "my-server", server_type=ServerType(name="cx11"), image=Image(name="ubuntu-16.04"), ssh_keys=[SSHKey(name="my-ssh-key")], volumes=[Volume(id=1)], user_data= "#cloud-config\\nruncmd:\\n- [touch, /root/cloud-init-worked]\\n", location=Location(name="nbg1"), automount=False) server = response.server action = response.action next_actions = response.next_actions root_password = response.root_password assert server.id == 42 assert server.volumes == [] assert server.server_type.id == 1 assert server.datacenter.id == 1 assert server.image.id == 4711 assert action.id == 1 assert action.command == "create_server" assert len(next_actions) == 1 assert next_actions[0].id == 13 assert next_actions[0].command == "start_server" assert root_password == "YItygq1v3GYjjMomLaKc" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_get_actions_list(self, hetzner_client, server): result = hetzner_client.servers.get_actions_list(server) actions = result.actions assert len(actions) == 1 assert actions[0].id == 13 assert actions[0].command == "start_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_update(self, hetzner_client, server): server = hetzner_client.servers.update(server, name="new-name", labels={}) assert server.id == 42 assert server.name == "new-name" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_delete(self, hetzner_client, server): action = hetzner_client.servers.delete(server) assert action.id == 13 assert action.command == "delete_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_power_off(self, hetzner_client, server): action = hetzner_client.servers.power_off(server) assert action.id == 13 assert action.command == "stop_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_power_on(self, hetzner_client, server): action = hetzner_client.servers.power_on(server) assert action.id == 13 assert action.command == "start_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_reboot(self, hetzner_client, server): action = hetzner_client.servers.reboot(server) assert action.id == 13 assert action.command == "reboot_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_reset(self, hetzner_client, server): action = hetzner_client.servers.reset(server) assert action.id == 13 assert action.command == "reset_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_shutdown(self, hetzner_client, server): action = hetzner_client.servers.shutdown(server) assert action.id == 13 assert action.command == "shutdown_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_reset_password(self, hetzner_client, server): response = hetzner_client.servers.reset_password(server) assert response.action.id == 13 assert response.action.command == "reset_password" assert response.root_password == "zCWbFhnu950dUTko5f40" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_type(self, hetzner_client, server): action = hetzner_client.servers.change_type(server, ServerType(name="cx11"), upgrade_disk=True) assert action.id == 13 assert action.command == "change_server_type" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_enable_rescue(self, hetzner_client, server): response = hetzner_client.servers.enable_rescue(server, type="linux64", ssh_keys=[2323]) assert response.action.id == 13 assert response.action.command == "enable_rescue" assert response.root_password == "zCWbFhnu950dUTko5f40" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_disable_rescue(self, hetzner_client, server): action = hetzner_client.servers.disable_rescue(server) assert action.id == 13 assert action.command == "disable_rescue" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create_image(self, hetzner_client, server): response = hetzner_client.servers.create_image(server, description="my image", type="snapshot") assert response.action.id == 13 assert response.action.command == "create_image" assert response.image.description == "my image" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_rebuild(self, hetzner_client, server): action = hetzner_client.servers.rebuild(server, Image(name="ubuntu-16.04")) assert action.id == 13 assert action.command == "rebuild_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_enable_backup(self, hetzner_client, server): action = hetzner_client.servers.enable_backup(server) assert action.id == 13 assert action.command == "enable_backup" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_disable_backup(self, hetzner_client, server): action = hetzner_client.servers.disable_backup(server) assert action.id == 13 assert action.command == "disable_backup" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_attach_iso(self, hetzner_client, server): action = hetzner_client.servers.attach_iso( server, Iso(name="FreeBSD-11.0-RELEASE-amd64-dvd1")) assert action.id == 13 assert action.command == "attach_iso" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_detach_iso(self, hetzner_client, server): action = hetzner_client.servers.detach_iso(server) assert action.id == 13 assert action.command == "detach_iso" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_dns_ptr(self, hetzner_client, server): action = hetzner_client.servers.change_dns_ptr(server, "1.2.3.4", "example.com") assert action.id == 13 assert action.command == "change_dns_ptr" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_protection(self, hetzner_client, server): action = hetzner_client.servers.change_protection(server, delete=True, rebuild=True) assert action.id == 13 assert action.command == "change_protection" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_request_console(self, hetzner_client, server): response = hetzner_client.servers.request_console(server) assert response.action.id == 13 assert response.action.command == "request_console" assert response.wss_url == "wss://console.hetzner.cloud/?server_id=1&token=3db32d15-af2f-459c-8bf8-dee1fd05f49c" assert response.password == "9MQaTg2VAGI0FIpc10k3UpRXcHj2wQ6x" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) @pytest.mark.parametrize( "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) def test_attach_to_network(self, hetzner_client, server, network): action = hetzner_client.servers.attach_to_network( server, network, ip="10.0.1.1", alias_ips=["10.0.1.2"]) assert action.id == 13 assert action.command == "attach_to_network" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) @pytest.mark.parametrize( "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) def test_detach_from_network(self, hetzner_client, server, network): action = hetzner_client.servers.detach_from_network(server, network) assert action.id == 13 assert action.command == "detach_from_network" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) @pytest.mark.parametrize( "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) def test_change_alias_ips(self, hetzner_client, server, network): action = hetzner_client.servers.change_alias_ips( server, network, alias_ips=["10.0.1.2"]) assert action.id == 13 assert action.command == "change_alias_ips"
def __init__(self, client, data, complete=True): algorithm = data.get("algorithm") if algorithm: data['algorithm'] = LoadBalancerAlgorithm(type=algorithm['type']) public_net = data.get("public_net") if public_net: ipv4_address = IPv4Address(**public_net['ipv4']) ipv6_network = IPv6Network(**public_net['ipv6']) data['public_net'] = PublicNetwork(ipv4=ipv4_address, ipv6=ipv6_network, enabled=public_net['enabled']) private_nets = data.get("private_net") if private_nets: private_nets = [ PrivateNet(network=BoundNetwork(client._client.networks, {"id": private_net['network']}, complete=False), ip=private_net['ip']) for private_net in private_nets ] data['private_net'] = private_nets targets = data.get("targets") if targets: tmp_targets = [] for target in targets: tmp_target = LoadBalancerTarget(type=target["type"]) if target["type"] == "server": tmp_target.server = BoundServer(client._client.servers, data=target['server'], complete=False) tmp_target.use_private_ip = target["use_private_ip"] elif target["type"] == "label_selector": tmp_target.label_selector = LoadBalancerTargetLabelSelector( selector=target['label_selector']['selector']) tmp_target.use_private_ip = target["use_private_ip"] elif target["type"] == "ip": tmp_target.ip = LoadBalancerTargetIP(ip=target['ip']['ip']) tmp_targets.append(tmp_target) data['targets'] = tmp_targets services = data.get("services") if services: tmp_services = [] for service in services: tmp_service = LoadBalancerService( protocol=service["protocol"], listen_port=service["listen_port"], destination_port=service["destination_port"], proxyprotocol=service["proxyprotocol"]) if service["protocol"] != "tcp": tmp_service.http = LoadBalancerServiceHttp( sticky_sessions=service['http']['sticky_sessions'], redirect_http=service['http']['redirect_http'], cookie_name=service['http']['cookie_name'], cookie_lifetime=service['http']['cookie_lifetime']) tmp_service.http.certificates = [ BoundCertificate(client._client.certificates, {"id": certificate}, complete=False) for certificate in service['http']['certificates'] ] tmp_service.health_check = LoadBalancerHealthCheck( protocol=service['health_check']['protocol'], port=service['health_check']['port'], interval=service['health_check']['interval'], retries=service['health_check']['retries'], timeout=service['health_check']['timeout']) if tmp_service.health_check.protocol != "tcp": tmp_service.health_check.http = LoadBalancerHealtCheckHttp( domain=service['health_check']['http']['domain'], path=service['health_check']['http']['path'], response=service['health_check']['http']['response'], tls=service['health_check']['http']['tls'], status_codes=service['health_check']['http'] ['status_codes']) tmp_services.append(tmp_service) data['services'] = tmp_services load_balancer_type = data.get("load_balancer_type") if load_balancer_type is not None: data['load_balancer_type'] = BoundLoadBalancerType( client._client.load_balancer_types, load_balancer_type) location = data.get("location") if location is not None: data['location'] = BoundLocation(client._client.locations, location) super(BoundLoadBalancer, self).__init__(client, data, complete)
class TestVolumesClient(object): def test_get_by_id(self, hetzner_client): bound_volume = hetzner_client.volumes.get_by_id(4711) assert bound_volume.id == 4711 assert bound_volume.name == "database-storage" assert bound_volume.size == 42 def test_get_by_name(self, hetzner_client): bound_volume = hetzner_client.volumes.get_by_name("database-storage") assert bound_volume.id == 4711 assert bound_volume.name == "database-storage" assert bound_volume.size == 42 def test_get_list(self, hetzner_client): result = hetzner_client.volumes.get_list() bound_volumes = result.volumes assert bound_volumes[0].id == 4711 assert bound_volumes[0].name == "database-storage" assert bound_volumes[0].size == 42 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create(self, hetzner_client, server): response = hetzner_client.volumes.create( 42, "test-database", location=Location(name="nbg1"), automount=False, format="xfs") volume = response.volume action = response.action next_actions = response.next_actions assert volume.id == 4711 assert volume.name == "database-storage" assert volume.size == 42 assert action.id == 13 assert action.command == "create_volume" assert len(next_actions) == 1 assert next_actions[0].id == 13 assert next_actions[0].command == "start_server" @pytest.mark.parametrize( "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_get_actions(self, hetzner_client, volume): actions = hetzner_client.volumes.get_actions(volume) assert len(actions) == 1 assert actions[0].id == 13 assert actions[0].command == "attach_volume" @pytest.mark.parametrize( "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_update(self, hetzner_client, volume): volume = hetzner_client.volumes.update(volume, name="new-name", labels={}) assert volume.id == 4711 assert volume.name == "new-name" @pytest.mark.parametrize( "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) def test_delete(self, hetzner_client, volume): delete_success = hetzner_client.volumes.delete(volume) assert delete_success is True @pytest.mark.parametrize("server,volume", [(Server(id=43), Volume(id=4711)), (BoundServer(mock.MagicMock(), dict(id=43)), BoundVolume(mock.MagicMock(), dict(id=4711)))]) def test_attach(self, hetzner_client, server, volume): action = hetzner_client.volumes.attach(volume, server) assert action.id == 13 assert action.progress == 0 assert action.command == "attach_volume" @pytest.mark.parametrize( "volume", [Volume(id=4711), BoundVolume(mock.MagicMock(), dict(id=4711))]) def test_detach(self, hetzner_client, volume): action = hetzner_client.volumes.detach(volume) assert action.id == 13 assert action.progress == 0 assert action.command == "detach_volume" @pytest.mark.parametrize( "volume", [Volume(id=4711), BoundVolume(mock.MagicMock(), dict(id=4711))]) def test_resize(self, hetzner_client, volume): action = hetzner_client.volumes.resize(volume, 50) assert action.id == 13 assert action.progress == 0 assert action.command == "resize_volume"
class TestFloatingIPsClient(object): @pytest.fixture() def floating_ips_client(self): return FloatingIPsClient(client=mock.MagicMock()) def test_get_by_id(self, floating_ips_client, floating_ip_response): floating_ips_client._client.request.return_value = floating_ip_response bound_floating_ip = floating_ips_client.get_by_id(1) floating_ips_client._client.request.assert_called_with( url="/floating_ips/1", method="GET") assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" def test_get_by_name(self, floating_ips_client, one_floating_ips_response): floating_ips_client._client.request.return_value = one_floating_ips_response bound_floating_ip = floating_ips_client.get_by_name("Web Frontend") floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="GET", params={"name": "Web Frontend"}) assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.name == "Web Frontend" assert bound_floating_ip.description == "Web Frontend" @pytest.mark.parametrize("params", [{ 'label_selector': "label1", 'page': 1, 'per_page': 10 }, { 'name': "" }, {}]) def test_get_list(self, floating_ips_client, two_floating_ips_response, params): floating_ips_client._client.request.return_value = two_floating_ips_response result = floating_ips_client.get_list(**params) floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="GET", params=params) bound_floating_ips = result.floating_ips assert result.meta is None assert len(bound_floating_ips) == 2 bound_floating_ip1 = bound_floating_ips[0] bound_floating_ip2 = bound_floating_ips[1] assert bound_floating_ip1._client is floating_ips_client assert bound_floating_ip1.id == 4711 assert bound_floating_ip1.description == "Web Frontend" assert bound_floating_ip2._client is floating_ips_client assert bound_floating_ip2.id == 4712 assert bound_floating_ip2.description == "Web Backend" @pytest.mark.parametrize("params", [{'label_selector': "label1"}, {}]) def test_get_all(self, floating_ips_client, two_floating_ips_response, params): floating_ips_client._client.request.return_value = two_floating_ips_response bound_floating_ips = floating_ips_client.get_all(**params) params.update({'page': 1, 'per_page': 50}) floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="GET", params=params) assert len(bound_floating_ips) == 2 bound_floating_ip1 = bound_floating_ips[0] bound_floating_ip2 = bound_floating_ips[1] assert bound_floating_ip1._client is floating_ips_client assert bound_floating_ip1.id == 4711 assert bound_floating_ip1.description == "Web Frontend" assert bound_floating_ip2._client is floating_ips_client assert bound_floating_ip2.id == 4712 assert bound_floating_ip2.description == "Web Backend" def test_create_with_location(self, floating_ips_client, floating_ip_response): floating_ips_client._client.request.return_value = floating_ip_response response = floating_ips_client.create( "ipv6", "Web Frontend", home_location=Location(name="location"), ) floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="POST", json={ 'description': "Web Frontend", 'type': "ipv6", 'home_location': "location" }) bound_floating_ip = response.floating_ip action = response.action assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" assert action is None @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create_with_server(self, floating_ips_client, server, floating_ip_create_response): floating_ips_client._client.request.return_value = floating_ip_create_response response = floating_ips_client.create(type="ipv6", description="Web Frontend", server=server) floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="POST", json={ 'description': "Web Frontend", 'type': "ipv6", 'server': 1 }) bound_floating_ip = response.floating_ip action = response.action assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" assert action.id == 13 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create_with_name(self, floating_ips_client, server, floating_ip_create_response): floating_ips_client._client.request.return_value = floating_ip_create_response response = floating_ips_client.create(type="ipv6", description="Web Frontend", name="Web Frontend") floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="POST", json={ 'description': "Web Frontend", 'type': "ipv6", 'name': "Web Frontend" }) bound_floating_ip = response.floating_ip action = response.action assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" assert bound_floating_ip.name == "Web Frontend" assert action.id == 13 @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_get_actions(self, floating_ips_client, floating_ip, response_get_actions): floating_ips_client._client.request.return_value = response_get_actions actions = floating_ips_client.get_actions(floating_ip) floating_ips_client._client.request.assert_called_with( url="/floating_ips/1/actions", method="GET", params={ 'page': 1, 'per_page': 50 }) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0]._client == floating_ips_client._client.actions assert actions[0].id == 13 assert actions[0].command == "assign_floating_ip" @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_update(self, floating_ips_client, floating_ip, response_update_floating_ip): floating_ips_client._client.request.return_value = response_update_floating_ip floating_ip = floating_ips_client.update(floating_ip, description="New description", name="New name") floating_ips_client._client.request.assert_called_with( url="/floating_ips/1", method="PUT", json={ "description": "New description", "name": "New name" }) assert floating_ip.id == 4711 assert floating_ip.description == "New description" assert floating_ip.name == "New name" @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_change_protection(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.change_protection(floating_ip, True) floating_ips_client._client.request.assert_called_with( url="/floating_ips/1/actions/change_protection", method="POST", json={"delete": True}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_delete(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action delete_success = floating_ips_client.delete(floating_ip) floating_ips_client._client.request.assert_called_with( url="/floating_ips/1", method="DELETE") assert delete_success is True @pytest.mark.parametrize("server,floating_ip", [(Server(id=1), FloatingIP(id=12)), (BoundServer(mock.MagicMock(), dict(id=1)), BoundFloatingIP(mock.MagicMock(), dict(id=12)))] ) def test_assign(self, floating_ips_client, server, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.assign(floating_ip, server) floating_ips_client._client.request.assert_called_with( url="/floating_ips/12/actions/assign", method="POST", json={"server": 1}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=12), BoundFloatingIP(mock.MagicMock(), dict(id=12))]) def test_unassign(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.unassign(floating_ip) floating_ips_client._client.request.assert_called_with( url="/floating_ips/12/actions/unassign", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=12), BoundFloatingIP(mock.MagicMock(), dict(id=12))]) def test_change_dns_ptr(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.change_dns_ptr(floating_ip, "1.2.3.4", "server02.example.com") floating_ips_client._client.request.assert_called_with( url="/floating_ips/12/actions/change_dns_ptr", method="POST", json={ "ip": "1.2.3.4", "dns_ptr": "server02.example.com" }) assert action.id == 1 assert action.progress == 0
class TestBoundFloatingIP(object): @pytest.fixture() def bound_floating_ip(self, hetzner_client): return BoundFloatingIP(client=hetzner_client.floating_ips, data=dict(id=14)) def test_bound_floating_ip_init(self, floating_ip_response): bound_floating_ip = BoundFloatingIP( client=mock.MagicMock(), data=floating_ip_response['floating_ip']) assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" assert bound_floating_ip.name == "Web Frontend" assert bound_floating_ip.ip == "131.232.99.1" assert bound_floating_ip.type == "ipv4" assert bound_floating_ip.protection == {"delete": False} assert bound_floating_ip.labels == {} assert bound_floating_ip.blocked is False assert isinstance(bound_floating_ip.server, BoundServer) assert bound_floating_ip.server.id == 42 assert isinstance(bound_floating_ip.home_location, BoundLocation) assert bound_floating_ip.home_location.id == 1 assert bound_floating_ip.home_location.name == "fsn1" assert bound_floating_ip.home_location.description == "Falkenstein DC Park 1" assert bound_floating_ip.home_location.country == "DE" assert bound_floating_ip.home_location.city == "Falkenstein" assert bound_floating_ip.home_location.latitude == 50.47612 assert bound_floating_ip.home_location.longitude == 12.370071 def test_get_actions(self, hetzner_client, bound_floating_ip, response_get_actions): hetzner_client.request.return_value = response_get_actions actions = bound_floating_ip.get_actions(sort="id") hetzner_client.request.assert_called_with( url="/floating_ips/14/actions", method="GET", params={ "sort": "id", 'page': 1, 'per_page': 50 }) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0].id == 13 assert actions[0].command == "assign_floating_ip" def test_update(self, hetzner_client, bound_floating_ip, response_update_floating_ip): hetzner_client.request.return_value = response_update_floating_ip floating_ip = bound_floating_ip.update(description="New description", name="New name") hetzner_client.request.assert_called_with(url="/floating_ips/14", method="PUT", json={ "description": "New description", "name": "New name" }) assert floating_ip.id == 4711 assert floating_ip.description == "New description" assert floating_ip.name == "New name" def test_delete(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action delete_success = bound_floating_ip.delete() hetzner_client.request.assert_called_with(url="/floating_ips/14", method="DELETE") assert delete_success is True def test_change_protection(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.change_protection(True) hetzner_client.request.assert_called_with( url="/floating_ips/14/actions/change_protection", method="POST", json={"delete": True}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) def test_assign(self, hetzner_client, bound_floating_ip, server, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.assign(server) hetzner_client.request.assert_called_with( url="/floating_ips/14/actions/assign", method="POST", json={"server": 1}) assert action.id == 1 assert action.progress == 0 def test_unassign(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.unassign() hetzner_client.request.assert_called_with( url="/floating_ips/14/actions/unassign", method="POST") assert action.id == 1 assert action.progress == 0 def test_change_dns_ptr(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.change_dns_ptr("1.2.3.4", "server02.example.com") hetzner_client.request.assert_called_with( url="/floating_ips/14/actions/change_dns_ptr", method="POST", json={ "ip": "1.2.3.4", "dns_ptr": "server02.example.com" }) assert action.id == 1 assert action.progress == 0
class TestFloatingIPsClient(object): def test_get_by_id(self, hetzner_client): bound_floating_ip = hetzner_client.floating_ips.get_by_id(4711) assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" assert bound_floating_ip.type == "ipv4" def test_get_list(self, hetzner_client): result = hetzner_client.floating_ips.get_list() bound_floating_ips = result.floating_ips assert bound_floating_ips[0].id == 4711 assert bound_floating_ips[0].description == "Web Frontend" assert bound_floating_ips[0].type == "ipv4" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create(self, hetzner_client, server): response = hetzner_client.floating_ips.create( type="ipv4", description="Web Frontend", # home_location=Location(description="fsn1"), server=server) floating_ip = response.floating_ip action = response.action assert floating_ip.id == 4711 assert floating_ip.description == "Web Frontend" assert floating_ip.type == "ipv4" assert action.id == 13 assert action.command == "assign_floating_ip" @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_get_actions(self, hetzner_client, floating_ip): actions = hetzner_client.floating_ips.get_actions(floating_ip) assert len(actions) == 1 assert actions[0].id == 13 assert actions[0].command == "assign_floating_ip" @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_update(self, hetzner_client, floating_ip): floating_ip = hetzner_client.floating_ips.update( floating_ip, description="New description", labels={}) assert floating_ip.id == 4711 assert floating_ip.description == "New description" @pytest.mark.parametrize( "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) def test_delete(self, hetzner_client, floating_ip): delete_success = hetzner_client.floating_ips.delete(floating_ip) assert delete_success is True @pytest.mark.parametrize( "server,floating_ip", [(Server(id=43), FloatingIP(id=4711)), (BoundServer(mock.MagicMock(), dict(id=43)), BoundFloatingIP(mock.MagicMock(), dict(id=4711)))]) def test_assign(self, hetzner_client, server, floating_ip): action = hetzner_client.floating_ips.assign(floating_ip, server) assert action.id == 13 assert action.progress == 0 assert action.command == "assign_floating_ip" @pytest.mark.parametrize("floating_ip", [ FloatingIP(id=4711), BoundFloatingIP(mock.MagicMock(), dict(id=4711)) ]) def test_unassign(self, hetzner_client, floating_ip): action = hetzner_client.floating_ips.unassign(floating_ip) assert action.id == 13 assert action.progress == 0 assert action.command == "unassign_floating_ip" @pytest.mark.parametrize("floating_ip", [ FloatingIP(id=4711), BoundFloatingIP(mock.MagicMock(), dict(id=4711)) ]) def test_change_dns_ptr(self, hetzner_client, floating_ip): action = hetzner_client.floating_ips.change_dns_ptr( floating_ip, "1.2.3.4", "server02.example.com") assert action.id == 13 assert action.progress == 0 assert action.command == "change_dns_ptr"
def bound_server(self, hetzner_client): return BoundServer(client=hetzner_client.servers, data=dict(id=14))
class TestServersClient(object): @pytest.fixture() def servers_client(self): return ServersClient(client=mock.MagicMock()) def test_get_by_id(self, servers_client, response_simple_server): servers_client._client.request.return_value = response_simple_server bound_server = servers_client.get_by_id(1) servers_client._client.request.assert_called_with(url="/servers/1", method="GET") assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" @pytest.mark.parametrize("params", [{ 'name': "server1", 'label_selector': "label1", 'page': 1, 'per_page': 10 }, { 'name': "" }, {}]) def test_get_list(self, servers_client, response_simple_servers, params): servers_client._client.request.return_value = response_simple_servers result = servers_client.get_list(**params) servers_client._client.request.assert_called_with(url="/servers", method="GET", params=params) bound_servers = result.servers assert result.meta is None assert len(bound_servers) == 2 bound_server1 = bound_servers[0] bound_server2 = bound_servers[1] assert bound_server1._client is servers_client assert bound_server1.id == 1 assert bound_server1.name == "my-server" assert bound_server2._client is servers_client assert bound_server2.id == 2 assert bound_server2.name == "my-server2" @pytest.mark.parametrize("params", [{ 'name': "server1", 'label_selector': "label1" }, {}]) def test_get_all(self, servers_client, response_simple_servers, params): servers_client._client.request.return_value = response_simple_servers bound_servers = servers_client.get_all(**params) params.update({'page': 1, 'per_page': 50}) servers_client._client.request.assert_called_with(url="/servers", method="GET", params=params) assert len(bound_servers) == 2 bound_server1 = bound_servers[0] bound_server2 = bound_servers[1] assert bound_server1._client is servers_client assert bound_server1.id == 1 assert bound_server1.name == "my-server" assert bound_server2._client is servers_client assert bound_server2.id == 2 assert bound_server2.name == "my-server2" def test_get_by_name(self, servers_client, response_simple_servers): servers_client._client.request.return_value = response_simple_servers bound_server = servers_client.get_by_name("my-server") params = {'name': "my-server"} servers_client._client.request.assert_called_with(url="/servers", method="GET", params=params) assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" def test_create_with_datacenter(self, servers_client, response_create_simple_server): servers_client._client.request.return_value = response_create_simple_server response = servers_client.create("my-server", server_type=ServerType(name="cx11"), image=Image(id=4711), datacenter=Datacenter(id=1)) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ 'name': "my-server", 'server_type': "cx11", 'image': 4711, 'datacenter': 1, "start_after_create": True }) bound_server = response.server assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" def test_create_with_location(self, servers_client, response_create_simple_server): servers_client._client.request.return_value = response_create_simple_server response = servers_client.create("my-server", server_type=ServerType(name="cx11"), image=Image(name="ubuntu-20.04"), location=Location(name="fsn1")) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ 'name': "my-server", 'server_type': "cx11", 'image': "ubuntu-20.04", 'location': "fsn1", "start_after_create": True }) bound_server = response.server bound_action = response.action assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" assert isinstance(bound_action, BoundAction) assert bound_action._client == servers_client._client.actions assert bound_action.id == 1 assert bound_action.command == "create_server" def test_create_with_volumes(self, servers_client, response_create_simple_server): servers_client._client.request.return_value = response_create_simple_server volumes = [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=2))] response = servers_client.create("my-server", server_type=ServerType(name="cx11"), image=Image(id=4711), volumes=volumes, start_after_create=False) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ 'name': "my-server", 'server_type': "cx11", 'image': 4711, 'volumes': [1, 2], "start_after_create": False }) bound_server = response.server bound_action = response.action next_actions = response.next_actions root_password = response.root_password assert root_password == "YItygq1v3GYjjMomLaKc" assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" assert isinstance(bound_action, BoundAction) assert bound_action._client == servers_client._client.actions assert bound_action.id == 1 assert bound_action.command == "create_server" assert next_actions[0].id == 13 def test_create_with_networks(self, servers_client, response_create_simple_server): servers_client._client.request.return_value = response_create_simple_server networks = [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=2))] response = servers_client.create("my-server", server_type=ServerType(name="cx11"), image=Image(id=4711), networks=networks, start_after_create=False) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ 'name': "my-server", 'server_type': "cx11", 'image': 4711, 'networks': [1, 2], "start_after_create": False }) bound_server = response.server bound_action = response.action next_actions = response.next_actions root_password = response.root_password assert root_password == "YItygq1v3GYjjMomLaKc" assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" assert isinstance(bound_action, BoundAction) assert bound_action._client == servers_client._client.actions assert bound_action.id == 1 assert bound_action.command == "create_server" assert next_actions[0].id == 13 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_get_actions_list(self, servers_client, server, response_get_actions): servers_client._client.request.return_value = response_get_actions result = servers_client.get_actions_list(server) servers_client._client.request.assert_called_with( url="/servers/1/actions", method="GET", params={}) actions = result.actions assert result.meta is None assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0]._client == servers_client._client.actions assert actions[0].id == 13 assert actions[0].command == "start_server" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_update(self, servers_client, server, response_update_server): servers_client._client.request.return_value = response_update_server server = servers_client.update(server, name="new-name", labels={}) servers_client._client.request.assert_called_with(url="/servers/1", method="PUT", json={ "name": "new-name", "labels": {} }) assert server.id == 14 assert server.name == "new-name" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_delete(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.delete(server) servers_client._client.request.assert_called_with(url="/servers/1", method="DELETE") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_power_off(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.power_off(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/poweroff", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_power_on(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.power_on(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/poweron", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_reboot(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.reboot(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/reboot", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_reset(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.reset(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/reset", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_shutdown(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.shutdown(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/shutdown", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_reset_password(self, servers_client, server, response_server_reset_password): servers_client._client.request.return_value = response_server_reset_password response = servers_client.reset_password(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/reset_password", method="POST") assert response.action.id == 1 assert response.action.progress == 0 assert response.root_password == "YItygq1v3GYjjMomLaKc" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_type_with_server_type_name(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.change_type(server, ServerType(name="cx11"), upgrade_disk=True) servers_client._client.request.assert_called_with( url="/servers/1/actions/change_type", method="POST", json={ "server_type": "cx11", "upgrade_disk": True }) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_type_with_server_type_id(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.change_type(server, ServerType(id=1), upgrade_disk=True) servers_client._client.request.assert_called_with( url="/servers/1/actions/change_type", method="POST", json={ "server_type": 1, "upgrade_disk": True }) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_type_with_blank_server_type(self, servers_client, server): with pytest.raises(ValueError) as e: servers_client.change_type(server, ServerType(), upgrade_disk=True) assert str(e.value) == "id or name must be set" servers_client._client.request.assert_not_called() @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_enable_rescue(self, servers_client, server, response_server_enable_rescue): servers_client._client.request.return_value = response_server_enable_rescue response = servers_client.enable_rescue(server, "linux64", [2323]) servers_client._client.request.assert_called_with( url="/servers/1/actions/enable_rescue", method="POST", json={ "type": "linux64", "ssh_keys": [2323] }) assert response.action.id == 1 assert response.action.progress == 0 assert response.root_password == "YItygq1v3GYjjMomLaKc" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_disable_rescue(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.disable_rescue(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/disable_rescue", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_create_image(self, servers_client, server, response_server_create_image): servers_client._client.request.return_value = response_server_create_image response = servers_client.create_image(server, description="my image", type="snapshot", labels={"key": "value"}) servers_client._client.request.assert_called_with( url="/servers/1/actions/create_image", method="POST", json={ "description": "my image", "type": "snapshot", "labels": { "key": "value" } }) assert response.action.id == 1 assert response.action.progress == 0 assert response.image.description == "my image" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_rebuild(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.rebuild(server, Image(name="ubuntu-20.04")) servers_client._client.request.assert_called_with( url="/servers/1/actions/rebuild", method="POST", json={"image": "ubuntu-20.04"}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_enable_backup(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.enable_backup(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/enable_backup", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_disable_backup(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.disable_backup(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/disable_backup", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_attach_iso(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.attach_iso( server, Iso(name="FreeBSD-11.0-RELEASE-amd64-dvd1")) servers_client._client.request.assert_called_with( url="/servers/1/actions/attach_iso", method="POST", json={"iso": "FreeBSD-11.0-RELEASE-amd64-dvd1"}) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_detach_iso(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.detach_iso(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/detach_iso", method="POST") assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_dns_ptr(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.change_dns_ptr(server, "1.2.3.4", "example.com") servers_client._client.request.assert_called_with( url="/servers/1/actions/change_dns_ptr", method="POST", json={ "ip": "1.2.3.4", "dns_ptr": "example.com" }) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_change_protection(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.change_protection(server, True, True) servers_client._client.request.assert_called_with( url="/servers/1/actions/change_protection", method="POST", json={ "delete": True, "rebuild": True }) assert action.id == 1 assert action.progress == 0 @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) def test_request_console(self, servers_client, server, response_server_request_console): servers_client._client.request.return_value = response_server_request_console response = servers_client.request_console(server) servers_client._client.request.assert_called_with( url="/servers/1/actions/request_console", method="POST") assert response.action.id == 1 assert response.action.progress == 0 assert response.wss_url == "wss://console.hetzner.cloud/?server_id=1&token=3db32d15-af2f-459c-8bf8-dee1fd05f49c" assert response.password == "9MQaTg2VAGI0FIpc10k3UpRXcHj2wQ6x" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) @pytest.mark.parametrize( "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) def test_attach_to_network(self, servers_client, server, network, response_attach_to_network): servers_client._client.request.return_value = response_attach_to_network action = servers_client.attach_to_network(server, network, "10.0.1.1", ["10.0.1.2", "10.0.1.3"]) servers_client._client.request.assert_called_with( url="/servers/1/actions/attach_to_network", method="POST", json={ "network": 4711, "ip": "10.0.1.1", "alias_ips": ["10.0.1.2", "10.0.1.3"] }) assert action.id == 1 assert action.progress == 0 assert action.command == "attach_to_network" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) @pytest.mark.parametrize( "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) def test_detach_from_network(self, servers_client, server, network, response_detach_from_network): servers_client._client.request.return_value = response_detach_from_network action = servers_client.detach_from_network(server, network) servers_client._client.request.assert_called_with( url="/servers/1/actions/detach_from_network", method="POST", json={"network": 4711}) assert action.id == 1 assert action.progress == 0 assert action.command == "detach_from_network" @pytest.mark.parametrize( "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) @pytest.mark.parametrize( "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) def test_change_alias_ips(self, servers_client, server, network, response_change_alias_ips): servers_client._client.request.return_value = response_change_alias_ips action = servers_client.change_alias_ips(server, network, ["10.0.1.2", "10.0.1.3"]) servers_client._client.request.assert_called_with( url="/servers/1/actions/change_alias_ips", method="POST", json={ "network": 4711, "alias_ips": ["10.0.1.2", "10.0.1.3"] }) assert action.id == 1 assert action.progress == 0 assert action.command == "change_alias_ips"
def test_bound_server_init(self, response_full_server): bound_server = BoundServer(client=mock.MagicMock(), data=response_full_server['server']) assert bound_server.id == 42 assert bound_server.name == "my-server" assert bound_server.primary_disk_size == 20 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.firewalls, list) assert isinstance(bound_server.public_net.firewalls[0], PublicNetworkFirewall) firewall = bound_server.public_net.firewalls[0] assert isinstance(firewall.firewall, BoundFirewall) assert bound_server.public_net.ipv6.blocked is False assert firewall.status == PublicNetworkFirewall.STATUS_APPLIED 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 assert bound_server.datacenter.id == 1 assert bound_server.datacenter.complete is True assert isinstance(bound_server.server_type, BoundServerType) assert bound_server.server_type._client == bound_server._client._client.server_types assert bound_server.server_type.id == 1 assert bound_server.server_type.complete is True assert len(bound_server.volumes) == 2 assert isinstance(bound_server.volumes[0], BoundVolume) assert bound_server.volumes[ 0]._client == bound_server._client._client.volumes assert bound_server.volumes[0].id == 1 assert bound_server.volumes[0].complete is False assert isinstance(bound_server.volumes[1], BoundVolume) assert bound_server.volumes[ 1]._client == bound_server._client._client.volumes assert bound_server.volumes[1].id == 2 assert bound_server.volumes[1].complete is False assert isinstance(bound_server.image, BoundImage) assert bound_server.image._client == bound_server._client._client.images assert bound_server.image.id == 4711 assert bound_server.image.name == "ubuntu-20.04" assert bound_server.image.complete is True assert isinstance(bound_server.iso, BoundIso) assert bound_server.iso._client == bound_server._client._client.isos assert bound_server.iso.id == 4711 assert bound_server.iso.name == "FreeBSD-11.0-RELEASE-amd64-dvd1" assert bound_server.iso.complete is True assert len(bound_server.private_net) == 1 assert isinstance(bound_server.private_net[0], PrivateNet) assert bound_server.private_net[ 0].network._client == bound_server._client._client.networks assert bound_server.private_net[0].ip == "10.1.1.5" assert bound_server.private_net[0].mac_address == "86:00:ff:2a:7d:e1" assert len(bound_server.private_net[0].alias_ips) == 1 assert bound_server.private_net[0].alias_ips[0] == "10.1.1.8"