Skip to content

feat(hetzner): add Hetzner Cloud infrastructure support - #110

Open
ingolevin wants to merge 3 commits into
exasol:mainfrom
ingolevin:il.hetzner
Open

ingolevin wants to merge 3 commits into
exasol:mainfrom
ingolevin:il.hetzner

Conversation

@ingolevin

@ingolevin ingolevin commented May 13, 2026

Copy link
Copy Markdown

Description

Add full Hetzner Cloud support to Exasol Personal, including infrastructure provisioning, cleanup provider, and power state management via the Hetzner Cloud API.

Related Issue

None

Fixes #

Type of Change

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation update
  • test: Test additions or changes
  • refactor: Code refactoring
  • chore: Maintenance tasks

Changes Made

New Infrastructure Preset: Hetzner Cloud

  • Location: assets/infrastructure/hetzner/
  • Components: Network, subnets, servers (ccx33 default), volumes, firewall, SSH keys, TLS certificates
  • OS: Ubuntu 22.04 LTS with cloud-init configuration
  • Features: Single/multi-node clusters, separate data volumes, generated passwords (20-char, mixed case + special chars)

Cloud-init Fixes

Hetzner Ubuntu images use root as the default user, but Exasol expects ubuntu:

  • Added cloudconf/10-create-ubuntu-user.yaml to create the ubuntu user with correct SSH authorized keys
  • Injects SSH public key via cloud-init template to avoid timing issues with Hetzner's key injection
  • Populates known_hosts with a retry loop so the barrier client can SSH to itself on the private network

Power State Management

  • exasol stop and exasol start call the Hetzner Cloud API directly from Go using the hcloud-go/v2 SDK
  • Server IDs are read from deployment.json at stop/start time — no Terraform state involvement
  • Graceful shutdown attempted first; falls back to forced poweroff on failure
  • Waits for the API action to complete before returning
  • HCLOUD_TOKEN must be set in the environment for stop/start to work
  • Infrastructure manifest declares powerControl.provider: hetzner to enable this behaviour

Cleanup Provider

  • New package: tools/cleanup/internal/hetzner/
  • Discovers and deletes: servers, volumes, networks, firewalls, SSH keys
  • Uses Hetzner resource labels (deployment_id) for scoped discovery
  • Integrated with exasol-cleanup CLI

Testing

  • All existing tests pass (task all)
  • Added new tests for new functionality
  • Manually tested: exasol install, exasol stop, exasol start, exasol-cleanup

Test Details

Manually verified on a live Hetzner deployment:

  • Full install with SSH access and database connectivity
  • exasol stop shuts down the VM via API and updates workflow state
  • exasol start powers on the VM via API, waits for it to be reachable, then updates workflow state
  • exasol-cleanup discovers and removes all Hetzner resources

Checklist

  • Code follows the project's coding guidelines
  • Ran task fmt and task lint
  • Updated documentation (if applicable)
  • Added/updated tests
  • All tests pass locally
  • Commit messages follow Conventional Commits format

Additional Notes

The HCLOUD_TOKEN environment variable must be set for all operations (install, stop, start, cleanup). It is used by both OpenTofu (via the hcloud provider) and the Go launcher (for direct API calls during stop/start).

ingolevin added 2 commits May 14, 2026 02:18
Add complete Hetzner Cloud infrastructure preset for Exasol Personal deployment:

Infrastructure:
- Add Terraform configs for Hetzner Cloud (network, servers, volumes, firewall)
- Support single-node and multi-node clusters
- Default server type: ccx33 (8 vCPU, 32GB RAM)
- Default location: fsn1 (Falkenstein)
- OS: Ubuntu 22.04 LTS with cloud-init fixes

Cloud-init fixes:
- Create 'ubuntu' user (Hetzner uses root by default)
- Copy SSH authorized_keys for barrier client

Power state management:
- Implement stop/start via Hetzner API using null_resource
- Support 'exasol stop' and 'exasol start' commands

Cleanup provider:
- Add Hetzner cleanup tool support (servers, volumes, networks, firewalls, SSH keys)
- Integrate with existing cleanup CLI

Documentation:
- Add Hetzner setup guide (HOWTO_SETUP_HETZNER_ACCOUNT.md)
- Update README with Hetzner in supported platforms
- Add Hetzner to test matrix (disabled by default)
@ingolevin
ingolevin marked this pull request as ready for review May 14, 2026 00:18
@ingolevin
ingolevin requested a review from a team as a code owner May 14, 2026 00:18
@wizenink

Copy link
Copy Markdown
Collaborator

This looks good, let's wait for monday when #102 is merged to rebase it here and check for needed changes.
Thank you!

Comment thread tools/bin/exasol-cleanup Outdated
Comment thread internal/deploy/deploymentControl.go
@migroble

migroble commented May 15, 2026

Copy link
Copy Markdown
Contributor

Thanks for your contribution! I can't really test it, but it looks good overall.

I would prefer if all the infrastructure stuff was contained to the presets though. I think it should be possible by using the hcloud_server_poweroff and hcloud_server_poweron actions triggered after an update based on the power_state variable. Something like:

resource "hcloud_server" "nodes" {
  lifecycle {
    action_trigger {
      events     = [ after_update ]
      conditions = var.power_state == "stopped"
      actions    = [ action.hcloud_server_poweroff.power_nodes_off ]
    }

    action_trigger {
      events     = [ after_update ]
      conditions = var.power_state == "running"
      actions    = [ action.hcloud_server_poweron.power_nodes_on ]
    }
  }

  # ...
}

What do you think?

@ingolevin

ingolevin commented May 15, 2026

Copy link
Copy Markdown
Author

What do you think?

@migroble
Having done some research on hcloud_server_poweroff / hcloud_server_poweron :

These are Terraform/OpenTofu Actions; Actions are imperative, not declarative. They fire on every tofu apply (deploy, refresh etc). We want a trigger that only fires when intended ./exasol [stop|start] right?

EDIT:
It also appears that action_trigger in lifecycle is a HashiCorp Terraform 1.14+ feature and not yet available in OpenTofu.
OpenTofu's lifecycle block only supports create_before_destroy, prevent_destroy, ignore_changes, and replace_triggered_by.

@migroble

Copy link
Copy Markdown
Contributor

They fire on every tofu apply (deploy, refresh etc). We want a trigger that only fires when intended ./exasol [stop|start] right?

Yeah, events = [ after_update ] should limit it to only when the resources already exist i.e. on start and stop, unless I misunderstood the docs.

It also appears that action_trigger in lifecycle is a HashiCorp Terraform 1.14+ feature and not yet available in OpenTofu.

Oh, that's unfortunate, in that case you can safely ignore me. :D

@nh-exa

nh-exa commented May 18, 2026

Copy link
Copy Markdown
Collaborator

First, thanks for your contribution! We certainly want to get this merged as soon as we can.
I believe we got some prep work to do first though because we really would like to avoid that the Go code becomes too aware of specific cloud providers.

I think this PR should accelerate some of the plans we had anyway:

  1. create a infrastructure preset "backend" abstraction that would give more control about what is happening during command deployment lifecycle commands like "deploy", "start" or "destroy" to the infrastructure preset itself. So instead of hard-coding tofu commands in Go, we want to give the preset the freedom to define custom commands, work with external tools other than tofu etc.

  2. While we do maintain and can test with AWS, Azure and Exoscale accounts at the moment, we as Exasol won't able to maintain and test all possible cloud providers or other possible deployment infrastructure from our side at some point. That we add Hetzner to the portfolio of providers we support by ourselves is quite possible though.
    We have discussed plans to allow providing presets via git clone URLs like this already:
    exasol install git@github.com:some-other-org/their-custom-exasol-infra-preset.git git@github.com:some-other-person/their-custom-exasol-install-preset.git

... or something similar.

That would allow you and everybody else to develop, use and maintain presets that Exasol itself can't commit to maintain.

We'll discuss internally in the team if we can and want to accelerate these plans or make an exception for this PR.

But thanks for the contribution regardless. This is why we made it open source!

@nh-exa

nh-exa commented May 20, 2026

Copy link
Copy Markdown
Collaborator

@wizenink was so kind to create this PR for the hetzner cloud terraform provider. Let's hope they'll merge this in soon. Would be glad to avoid our workaround.

@ingolevin

Copy link
Copy Markdown
Author

Thank you for the feedback @nh-exa! I am looking forward on the decided way forward; no rush from my side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants