hetzner

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2024 License: MIT Imports: 16 Imported by: 0

README

Fleeting Plugin Hetzner

This is a fleeting plugin for Hetzner Cloud.

Pipeline Status Go Report Card

The project started out as a fork of the existing fleeting-plugin-aws plugin, gradually replacing the AWS calls with calls to the Hetzner Cloud API.

Building the plugin

To generate the binary, ensure $GOPATH/bin is on your PATH, then use go build:

cd cmd/fleeting-plugin-hetzner/
go build 

If you are managing go versions with asdf, run this after generating the binary:

asdf reshim

Plugin Configuration

The following parameters are supported:

Parameter Type Description
access_token string The Hetzner Cloud API token to use. Generate this in the Hetzner Cloud Console, for the project in which you want the cloud CI instances to be created.
location string The Hetzner location to use, from https://docs.hetzner.com/cloud/general/locations/
server_type string The server type to create, from https://docs.hetzner.com/cloud/servers/overview/
image string The operating system image to use. If you have the hcloud CLI installed, you can list available images using hcloud image list --type system.
Connector config

The connector config is currently hardwired as follows:

Parameter Value
os Only linux is supported.
protocol ssh (winrm is not supported)
username root; the Hetzner Cloud API does not seem to allow overriding this.
use_static_credentials false; a unique SSH private/public key will be created for each server created.
key_path None.

Examples

GitLab Runner

GitLab Runner has examples on using the other plugins for the Instance executor and Docker Autoscaler executor. Here is an incomplete example of how to use this plugin with the docker-autoscaler executor, starting from the runners.docker node. Both runners.docker and runners.autoscaler need to exist, because the autoscaler will otherwise complaining about "missing docker configuration".

# ...
  [runners.docker]
    tls_verify = false
    image = "busybox"

  [runners.autoscaler]
    plugin = "/path/to/fleeting-plugin-hetzner"

    capacity_per_instance = 1
    max_use_count = 1
    max_instances = 10

    # Set this if you want to connect using a public address. If you use private_networks, you can leave
    # this out (the default is 'false', i.e. connect using internal address only)
    [runners.autoscaler.connector_config]
      use_external_addr = true

    [runners.autoscaler.plugin_config] # plugin specific configuration (see plugin documentation)
      access_token      = "<insert-token-here>"
      location          = "hel1"
      server_type       = "cx11"

      # docker-ce is an "app" image provided by Hetzner which is based on Ubuntu 22.04, but provides
      # Docker CE preinstalled: https://docs.hetzner.com/cloud/apps/list/docker-ce/
      #
      # You could also use another image here, but it must have Docker installed.
      image             = "docker-ce"

      # All instances created by this plugin will have their server name prefixed with this name
      name              = "my-docker-autoscaler-group"

      # Public IPv4 and IPv6 are enabled on Hetzner by default. These can be disabled below, but you must
      # add one or more private networks in that case; otherwise the Hetzner cloud API will return errors
      # when we try to create instances. It is also possible to use public and private networks
      # simultaneously.
      disable_public_networks   = ["ipv4", "ipv6"]
      private_networks          = ["hetzner-cloud-ci-network"]

      # If you like to, you can specify a cloud-init configuration using one of the following forms (note,
      # both cannot be used simultaneously). The first example below is taken from
      # https://cloudinit.readthedocs.io/en/latest/reference/examples.html. Remember that the cloud-init
      # user-data must begin with #cloud-config, otherwise the file will be silently ignored.
      cloud_init_user_data = """
#cloud-config
users:
- name: ansible
  gecos: Ansible User
  groups: users,admin,wheel
  sudo: ALL=(ALL) NOPASSWD:ALL
  shell: /bin/bash
  lock_passwd: true
  ssh_authorized_keys:
    - "ssh-rsa AAAAB3NzaC1..."
    """
      cloud_init_user_data_file = "/path/to/cloud-init/user-data.yml"

    [[runners.autoscaler.policy]]
      idle_count        = 1
      idle_time         = "20m0s"

Testing the plugin locally

Running the unit tests is easy, and this is also done for each MR/commit to main on GitLab:

$ go test

Extending this to also run the integration test requires that you provide a valid FLEETING_PLUGIN_HETZNER_TOKEN environment variable. Something like this (or put it in your ~/.bashrc or similar):

$ FLEETING_PLUGIN_HETZNER_TOKEN=foo go test
Testing the plugin with GitLab Runner

Sometimes, you want to test the whole plugin as its being executed by GitLab's Fleeting mechanism. Use an approach like this:

  1. Build the plugin by running the following:

    $ cd cmd/fleeting-plugin-hetzner
    $ go build
    
  2. Set up the plugin in GitLab Runner's config.toml file using the approach described above, but update plugin = "/path/to/fleeting-plugin-hetzner" to point to your cmd/fleeting-plugin-hetzner/fleeting-plugin-hetzner

  3. Run gitlab-runner run or similar, to run GitLab Runner interactively as a foreground process.

  4. Make a CI job run using this runner, perhaps using special tags: or similar (to avoid breaking things for other CI jobs on the same GitLab installation).

Creating a new release

  1. Make sure the VERSION file is up-to-date
  2. Commit the changes to that file, using a commit message in line with this: git commit VERSION -m "Bump version to v0.2.0"
  3. Run make do-release. This creates a tag, which in turns triggers some CI logic in .gitlab/ci/release.gitlab-ci.yml which creates a GitLab release.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	NAME      = "fleeting-plugin-hetzner"
	VERSION   = "dev"
	REVISION  = "HEAD"
	REFERENCE = "HEAD"
	BUILT     = "now"

	Version VersionInfo
)

Functions

This section is empty.

Types

type InstanceGroup

type InstanceGroup struct {
	AccessToken           string   `json:"access_token"`
	Location              string   `json:"location"`
	ServerType            string   `json:"server_type"`
	Image                 string   `json:"image"`
	DisablePublicNetworks []string `json:"disable_public_networks"`
	PrivateNetworks       []string `json:"private_networks"`
	CloudInitUserData     string   `json:"cloud_init_user_data"`
	CloudInitUserDataFile string   `json:"cloud_init_user_data_file"`

	// Because of limitations in the Hetzner API, instance groups do not formally exist in the
	// Hetzner API. The Name here is mapped to a label which is set on all machines created in this
	// "instance group".
	Name string `json:"name"`
	// contains filtered or unexported fields
}

func (*InstanceGroup) ConnectInfo

func (g *InstanceGroup) ConnectInfo(ctx context.Context, id string) (provider.ConnectInfo, error)

func (*InstanceGroup) Decrease

func (g *InstanceGroup) Decrease(ctx context.Context, instances []string) ([]string, error)

func (*InstanceGroup) Increase

func (g *InstanceGroup) Increase(ctx context.Context, delta int) (int, error)

func (*InstanceGroup) Init

func (g *InstanceGroup) Init(ctx context.Context, log hclog.Logger, settings provider.Settings) (provider.ProviderInfo, error)

func (*InstanceGroup) Shutdown

func (g *InstanceGroup) Shutdown(ctx context.Context) error

func (*InstanceGroup) Update

func (g *InstanceGroup) Update(ctx context.Context, update func(id string, state provider.State)) error

type VersionInfo

type VersionInfo struct {
	Name         string `json:"name"`
	Version      string `json:"version"`
	Revision     string `json:"revision"`
	Reference    string `json:"reference"`
	GOVersion    string `json:"go_version"`
	BuiltAt      string `json:"built_at"`
	OS           string `json:"os"`
	Architecture string `json:"architecture"`
}

func (*VersionInfo) BuildInfo

func (v *VersionInfo) BuildInfo() string

func (*VersionInfo) Full

func (v *VersionInfo) Full() string

func (*VersionInfo) String

func (v *VersionInfo) String() string

Directories

Path Synopsis
cmd
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL