lsymds / hetznercloud-py

Python SDK for the new Hetzner cloud
MIT License
30 stars 12 forks source link

Hetzner Cloud Python SDK

DEPRECATED

THIS LIBRARY IS NO LONGER SUPPORTED. IT WILL RECEIVE NO UPDATES, NO SECURITY FIXES AND NO BUG FIXES. YOU SHOULD BE USING THE OFFICIAL HETZNERCLOUD PYTHON LIBRARY WHICH WAS RELEASED OVER 8 MONTHS AGO.

PROCEED AT YOUR OWN RISK!


License: MIT Build Status

A Python 3 SDK for the new (and wonderful) Hetzner cloud service.

Contributing

Open source contributions are more than welcome to be submitted to this repository and every issue and pull request will be promptly reviewed and evaluated on its suitability to be merged into the main branches.

Changelog

v1.1.1

v1.1.0

v1.0.4

v1.0.3

v1.0.2

Documentation

This library is organised into two components: the first, a set of actions that retrieve an actionable component. These actionable components (for example servers) each have their own methods that modify their own (and only their own) behaviour.

Installation

Install the library into your environment by executing the following command in your terminal:

pip install hetznercloud

Getting started

In order to get started with the library, you first need an instance of it. This is very simple, and uses a number of hand-crafted helper functions to make configuration changes.

from hetznercloud import HetznerCloudClientConfiguration, HetznerCloudClient

configuration = HetznerCloudClientConfiguration().with_api_key("YOUR-API-KEY").with_api_version(1)
client = HetznerCloudClient(configuration)

The client is your entry point to the SDK.

A note on actions

Methods that modify server state (such as creating, imaging, snapshotting, deleting etc) generally return a tuple. The first value of this tuple is normally the object type modified (i.e. a server), whilst the second value is the action.

The HetznerCloudAction object (second value in the tuple) can be used to wait for certain states of that invoked task to be achieved before continuing. For more information, see the Actions section.

Constants

The SDK contains a number of helpful constants that save you having to look up things such as image names, server types and so on.

Please note: I endeavour to keep the constants up to date, but sometimes it is just not possible. Should this happen, feel free to use plain-ole strings (i.e. cx11 for the smallest cloud instance) in their place until I get around to deploying the update.

Server statuses

Constants that represent the different statuses a server can have.

Action statuses

Constants that represent the different statuses an action can have.

Server types

Constants that represent the server types available to users.

Image types

Constants that represent the standard images available to users.

Datacentre constants

Constants that represent the datacentres available to users.

Backup windows

Constants that represent backup windows.

Floating IP types

Constants that represent floating IP types

Image types

Constants that represent image types.

Image sorts

Constants that define the different ways that images can be sorted.

Standard exceptions

A number of standard exceptions can be thrown from the methods that interact with the Hetzner API.

Datacenters

Top level actions

The datacenter top level action can be retrieved by calling the datacenters() method on the HetznerCloudClient instance.

Get all datacenters

To retrieve all of the datacenters available on the Hetzner Cloud service, simply call the get_all() method, passing in no parameters.

NOTE: This method returns a generator, so if you wish to get all of the results instantly, you should encapsulate the call within the list() function

all_dcs_generator = client.datacenters().get_all()
for dc in all_dcs_generator:
    print(dc.id)

all_dcs_list = list(client.datacenters().get_all())
print(all_dcs_list)
Get all datacenters by name

To get all datacenters filtered by a name, call the get_all() method with the name parameter populated.

all_dcs = list(client.datacenters().get_all(name="fsn1-dc8"))
print(all_dcs)
Get datacenter by id

To get a datacenter by id, simply call the get() method on the datacenter action, passing in the id of the datacenter you wish to get information for.

datacenter = client.datacenters().get(1)
print(datacenter.name)

Floating IPs

Floating IPs top level actions

Create floating IP

To create a floating IP, simply call the create() method with the parameters detailed below.

NOTE: If you do not specify server, then you must specify home_location, or vice versa.

new_floating_ip = client.floating_ips().create(type=FLOATING_IP_TYPE_IPv4,
    server=42,
    description="My new floating IP")

" or...

new_floating_ip = client.floating_ips().create(type=FLOATING_IP_TYPE_IPv4,
    home_location="fep1",
    description="My new floating IP")
Get all floating IPs
floating_ips = client.floating_ips().get_all()
for ip in floating_ips:
    print(ip.id)
Get floating IP by id
floating_ip = client.floating_ips().get(1)
print(floating_ip.id)

Floating IPs modifier actions

Assign floating IP to server
floating_ip = client.floating_ips().get(1)
action = floating_ip.assign_to_server(2)
action.wait_until_status_is(ACTION_STATUS_RUNNING)
Change floating IP description
floating_ip = client.floating_ips().get(1)
action = floating_ip.change_description("My new floating IP v2")
Change floating IP reverse DNS entry
floating_ip = client.floating_ips().get(1)
action = floating_ip.change_reverse_dns_entry("192.168.1.1", "www.google.com")
action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Delete floating IP
floating_ip = client.floating_ips().get(1)
action = floating_ip.delete()
Unassign floating IP from server
floating_ip = client.floating_ips().get(1)
action = floating_ip.unassign_from_server()

Images

Images top level actions

Get all images

To retrieve all of the images available on the Hetzner Cloud service, simply call the get_all() method, passing in no parameters.

There are also a number of parameters on this method that allow you to filter and sort images.

images = client.images().get_all(sort=SORT_BY_ID_ASC)
for image in images:
    print(image.id)
Get image by id

To get an image by its id, simply call the get() method, passing in the id of the image you wish to retrieve.

image = client.images().get(1)
print(image.id)

Images modifier actions

Update image

To update an image's description or type, call the update() method with the description of the image and/or the type of the image, should you wish to update them. Both parameters are optional.

image = client.images().get(1)
image.update(description="my description", type=IMAGE_TYPE_SNAPSHOT)
Delete image

To delete an image, call the delete() method. NOTE: Only images of type 'snapshot' or 'backup' can be deleted (so, you cannot delete the images provided by Hetzner!).

image = list(client.images().get_all(name="my-first-image"))[0]
image.delete()

ISOs

Top level actions

The iso top level action can be retrieved by calling the isos() method on the HetznerCloudClient instance.

Get all ISOs

To retrieve all of the isos available on the Hetzner Cloud service, simply call the get_all() method, passing in no parameters.

NOTE: This method returns a generator, so if you wish to get all of the results instantly, you should encapsulate the call within the list() function

isos = client.isos().get_all()
for l in isos:
    print(l.id)

isos = list(client.isos().get_all())
print(isos)
Get all ISOs by name

To get all isos filtered by a name, call the get_all() method with the name parameter populated.

isos = list(client.isos().get_all(name="virtio-win-0.1.141.iso"))
print(isos)
Get ISO by id

To get an iso by id, simply call the get() method on the datacenter action, passing in the id of the iso you wish to get information for.

iso = client.isos().get(1)
print(iso.name)

Locations

Top level actions

The location top level action can be retrieved by calling the locations() method on the HetznerCloudClient instance.

Get all locations

To retrieve all of the locations available on the Hetzner Cloud service, simply call the get_all() method, passing in no parameters.

NOTE: This method returns a generator, so if you wish to get all of the results instantly, you should encapsulate the call within the list() function

all_locs_generator = client.locations().get_all()
for l in all_locs_generator:
    print(l.id)

all_locs_list = list(client.locations().get_all())
print(all_locs_list)
Get all locations by name

To get all locations filtered by a name, call the get_all() method with the name parameter populated.

all_locs = list(client.locations().get_all(name="fsn1"))
print(all_locs)
Get location by id

To get a location by id, simply call the get() method on the datacenter action, passing in the id of the location you wish to get information for.

location = client.locations().get(1)
print(location.name)

Servers

The servers top level action is accessible through the client.servers() method. You must use one of the methods in the object returned by this top level action in order to modify the state of individual servers.

Server top level actions

Get all servers

All servers associated with the API key you provided can be retrieved by calling the get_all() top level action method.

all_servers = client.servers().get_all() # gets all the servers as a generator
all_servers_list = list(client.servers().get_all()) # gets all the servers as a list
Get all servers by name

By calling the get_all(name="my-server-name") method (with the optional name parameter entered), you can bring back the servers that have the name entered.

all_servers = client.servers().get_all(name="foo") # gets all the servers as a generator
all_servers_list = list(client.servers().get_all(name="foo")) # gets all the servers as a list
Get server by id

If you know the id of the server you wish to retrieve you can use this method to retrieve that specific server.

try:
    server = client.servers().get(1)
except HetznerServerNotFoundException:
    print("Woops, server not found!")

This method throws a HetznerServerNotFoundException if the following conditions are satisfied:

Create server

To create a server, you can call the create top level action method. This method accepts a number of parameters (some are optional, some aren't).

server_a, create_action = client.servers().create(name="my-required-server-name", # REQUIRED
    server_type=SERVER_TYPE_1CPU_2GB, # REQUIRED
    image=IMAGE_UBUNTU_1604, # REQUIRED
    datacenter=DATACENTER_FALKENSTEIN_1,
    start_after_create=True,
    ssh_keys=["my-ssh-key-1", "my-ssh-key-2"],
    user_data='''#cloud-config
    packages:
     - screen
     - git
    ''')
server_a.wait_until_status_is(SERVER_STATUS_RUNNING) 

For more details on user_data please see https://cloudinit.readthedocs.io/en/latest/topics/examples.html

Server modifier actions

Once you have an instance of the server (retrieved by using one of the "Top level actions" above), you are able to perform different modifier actions on them.

Attach ISO

To attach an ISO to the server, call the attach_iso() method on the HetznerCloudServer object, specifying either the name or the ID of the ISO you wish to attach to the server (these can be retrieved by using the isos().get_all() method on the client).

NOTE: Constants will not be provided for the ISOs, as they are too dynamic and likely to change.

server = client.servers().get(1)
iso_action = server.attach_iso("virtio-win-0.1.141.iso")
iso_action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Change reverse DNS

To change the reverse DNS record associated with the server, call the change_reverse_dns_entry() method on the HetznerCloudServer object, specifying the IP address you wish to add a record for and the reverse DNS record.

NOTE: If you leave the dns_pointer parameter as None, the reverse DNS record will be reverted back to what Hetzner set it as when they created your server.

server = client.servers().get(1)
action = server.change_reverse_dns_entry("192.168.1.1", "www.google.com")
Change server name

To change the server name, call the change_name() method on the HetznerCloudServer object, specifying a valid name as the first and only parameter.

NOTE: This method does not return an action, so it is assumed that the update is processed immediately. You can verify this assumption by renaming the server, immediately retrieving it by its id and checking the name of the retrieved server is what you renamed it to.

server = client.servers().get(1)
server.change_name("my-new-server-name")
Change server type

To change the server type (i.e. from a small, to a large instance), call the change_type() method on the HetznerCloudServer object, specifying the new server type as the first parameter and whether to resize the disk as the second parameter.

NOTE: Your server needs to be powered off in order for this to work.

NOTE: If you wish to downgrade the server type in the future, make sure you set the upgrade_disk parameter to False. Not doing this will result in an error being thrown should you try to downgrade in the future.

server = client.servers().get(1)
action = server.change_type(SERVER_TYPE_2CPU_4GB, False)

action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Delete server

To delete the server, call the delete() method on the HetznerCloudServer object.

server = client.servers().get(1)
action = server.delete()

# Wait until the delete action has completed.
action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Detach ISO

To detach the ISO from the server (if there is one present), call the detach_iso() method on the HetznerCloudServer object.

NOTE: Calling this method when no ISO is attached to the server will succeed and not throw an error.

server = client.servers.get(1)
action = server.detach_iso()

action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Disable rescue mode

To disable rescue mode on the server, simply call the disable_rescue_mode() on the server object.

NOTE: Although the API documentation says an error will be returned if rescue mode is already disabled, we have found this is not the case.

server = client.servers().get(1)
disable_action = server.disable_rescue_mode()

disable_action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Enable server backups

To enable server backups, simply call the enable_backups() method on the server object with your chosen backup window.

server = client.servers().get(1)
action = server.enable_backups(BACKUP_WINDOW_2AM_6AM)

This method throws a HetznerActionException if the backup window is not one of the valid choices (see: https://docs.hetzner.cloud/#resources-server-actions-post-11).

Enable rescue mode

To enable rescue mode, simply call the enable_rescue_mode() method on the server object. You can specify a rescue image and an array of SSH keys to load into it.

NOTE: If you use the FreeBSD rescue image, you will not be able to load in any SSH keys.

NOTE: If you want to use the rescue mode, you will need to reboot your server. This method will not automatically do that for you.

server = client.servers().get(1)
root_password, enable_action = server.enable_rescue_mode(rescue_type=RESCUE_TYPE_LINUX32, ssh_keys=["my-ssh-key"])

enable_action.wait_until_status_is(ACTION_STATUS_SUCCESS)

print("Your root password for the rescue mode is %s" % root_password)
Image server

To image a server (i.e. create a backup or a snapshot), call the image() method on the server object. You can specify the description of the server and the type of image you are creating. Possible image types are as follows:

server = client.servers().get(1)
image_id, image_action = server.image("My backup image", type=IMAGE_TYPE_BACKUP)

image_action.wait_until_status_is(ACTION_STATUS_SUCCESS)

print("The new backup image identifier is %s" % image_id)
Power on

To power a server on, simply call the power_on() method on the server object.

Power off

To power a server off, simply call the power_off() method on the server object.

Rebuild from image

To rebuild a server from an image, simply call the rebuild_from_image() method on the server object, passing in the image id or name you wish to overwrite the server with.

NOTE: This method will destroy all data on the server

server = client.servers().get(1)
action = server.rebuild_from_image(IMAGE_UBUNTU_1604)

action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Reset server

To reset a server (equivelent to pulling the power cord and plugging it back in), simply call the reset() method on the server object.

server = client.servers().get(1)
action = server.reset()
action.wait_until_status_is(ACTION_STATUS_SUCCESS)
Reset root password

To reset the password of the Root account on a server, simply call the reset_root_password() method on the server object.

server = client.servers().get(1)
root_password, reset_action = server.reset_root_password()

print("The new root password is %s" % root_password)
Shutdown server

To shutdown a server gracefully, simply call the shutdown() method on the server object.

NOTE: The OS on the server you are trying to shut down must support ACPI.

server = client.servers().get(1)
server.shutdown()
Wait for server status

You can wait for a server to have a particular status by calling the wait_until_status_is(desired_status) method on the server object.

This method will loop a set number of times (defined by the attempts parameter) and pause each time for one second (or a timespan defined by modifying the wait_seconds parameter) until the number of attempts is exceeded or the condition matches.

This is useful when you want to ensure your server is of a particular state before performing any actions on it.

server = client.servers().get(1)

try:
    server.wait_until_status_is(SERVER_STATUS_OFF, attempts=50, wait_seconds=10)
except HetznerWaitAttemptsExceededException:
    print("Server status was not updated in 50 attempts") 

This method throws a HetznerWaitAttemptsExceededException should the amount of attempts be exceeded with the condition still being unmet.

Server size types

Top level actions

The server types top level action can be retrieved by calling the server_types() method on the HetznerCloudClient instance.

Get all server types

To retrieve all of the server types available on the Hetzner Cloud service, simply call the get_all() method, passing in no parameters.

NOTE: This method returns a generator, so if you wish to get all of the results instantly, you should encapsulate the call within the list() function

types = client.server_types().get_all()
for l in types:
    print(l.id)

types = list(client.server_types().get_all())
print(types)
Get all server types by name

To get all server types filtered by a name, call the get_all() method with the name parameter populated.

server_types = list(client.server_types().get_all(name="cx11"))
print(server_types)
Get server type by id

To get a server type by id, simply call the get() method on the datacenter action, passing in the id of the server type you wish to get information for.

stype = client.server_types().get(1)
print(stype.name)

SSH keys

SSH keys top level actions

Create SSH key

To create an SSH key, call the create() method on the HetznerCloudSSHKeysAction with the name and the public key of the SSH key you wish to add.

new_ssh_key = client.ssh_keys().create(name="My new SSH key", public_key="abcdef")
print(new_ssh_key.fingerprint)
Get all SSH keys

To get all SSH keys, call the get_all() method. NOTE: This object returned from this method is a generator.

ssh_keys = client.ssh_keys().get_all()
for ssh_key in ssh_keys:
    print(ssh_key.id)
Get all SSH keys by name

To get all SSH keys by their name, call the get_all() method, but pass in the name of the SSH key you wish to search for.

ssh_keys = list(client.ssh_keys().get_all(name="My SSH key"))
for ssh_key in ssh_keys:
    print(ssh_key.id)
Get SSH key by id
ssh_key = client.ssh_keys().get(1)
print(ssh_key.id)

SSH keys modifier actions

Delete SSH key

To delete an SSH key, call the delete() method on the SSH key object.

ssh_key = client.ssh_keys().get(1)
ssh_key.delete()
Update SSH key

To update an SSH key's name, call the update() method on the SSH key object.

ssh_key = client.ssh_keys().get(1)
ssh_key.update(name="Foo")