hcloudimages

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 9, 2024 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package hcloudimages is a library to upload Disk Images into your Hetzner Cloud project.

Overview

The Hetzner Cloud API does not support uploading disk images directly, and it only provides a limited set of default images. The only option for custom disk images that users have is by taking a "snapshot" of an existing servers root disk. These can then be used to create new servers.

To create a completely custom disk image, users have to follow these steps:

  1. Create server with the correct server type
  2. Enable rescue system for the server
  3. Boot the server
  4. Download the disk image from within the rescue system
  5. Write disk image to servers root disk
  6. Shut down the server
  7. Take a snapshot of the servers root disk
  8. Delete the server

This is an annoyingly long process. Many users have automated this with Packer before, but Packer offers a lot of additional complexity to understand.

This library is a single call to do the above: Client.Upload

Costs

The temporary server and the snapshot itself cost money. See the Hetzner Cloud website for up-to-date pricing information.

Usually the upload takes no more than a few minutes of server time, so you will only be billed for the first hour (<1ct for most cases). If this process fails, the server might stay around until you manually delete it. In that case it continues to cost its hourly price. There is a utility [Client.CleanupTemporaryResources] that removes any leftover resources.

Logging

By default, nothing is logged. As the update process takes a bit of time you might want to gain some insight into the process. For this we provide optional logs through log/slog. You can set a log/slog.Logger in the context.Context through github.com/apricote/hcloud-upload-image/hcloudimages/contextlogger.New.

Index

Examples

Constants

View Source
const (
	CreatedByLabel = "apricote.de/created-by"
	CreatedByValue = "hcloud-upload-image"
)

Variables

View Source
var (
	DefaultLabels = map[string]string{
		CreatedByLabel: CreatedByValue,
	}
)

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

func NewClient

func NewClient(c *hcloud.Client) *Client

NewClient instantiates a new client. It requires a working *hcloud.Client to interact with the Hetzner Cloud API.

func (*Client) CleanupTempResources

func (s *Client) CleanupTempResources(ctx context.Context) error

CleanupTempResources tries to delete any resources that were left over from previous calls to Client.Upload. Upload tries to clean up any temporary resources it created at runtime, but might fail at any point. You can then use this command to make sure that all temporary resources are removed from your project.

This method tries to delete any server or ssh keys that match the DefaultLabels

func (*Client) Upload

func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Image, error)

Upload the specified image into a snapshot on Hetzner Cloud.

As the Hetzner Cloud API has no direct way to upload images, we create a temporary server, overwrite the root disk and take a snapshot of that disk instead.

The temporary server costs money. If the upload fails, we might be unable to delete the server. Check out CleanupTempResources for a helper in this case.

Example
package main

import (
	"context"
	"fmt"
	"net/url"

	"github.com/hetznercloud/hcloud-go/v2/hcloud"

	"github.com/apricote/hcloud-upload-image/hcloudimages"
)

func main() {
	client := hcloudimages.NewClient(
		hcloud.NewClient(hcloud.WithToken("<your token>")),
	)

	imageURL, err := url.Parse("https://example.com/disk-image.raw.bz2")
	if err != nil {
		panic(err)
	}

	image, err := client.Upload(context.TODO(), hcloudimages.UploadOptions{
		ImageURL:         imageURL,
		ImageCompression: hcloudimages.CompressionBZ2,
		Architecture:     hcloud.ArchitectureX86,
	})
	if err != nil {
		panic(err)
	}

	fmt.Printf("Uploaded Image: %d", image.ID)
}
Output:

type Compression

type Compression string
const (
	CompressionNone Compression = ""
	CompressionBZ2  Compression = "bz2"
	CompressionXZ   Compression = "xz"
)

type UploadOptions

type UploadOptions struct {
	// ImageURL must be publicly available. The instance will download the image from this endpoint.
	ImageURL *url.URL

	// ImageReader
	ImageReader io.Reader

	// ImageCompression describes the compression of the referenced image file. It defaults to [CompressionNone]. If
	// set to anything else, the file will be decompressed before written to the disk.
	ImageCompression Compression

	// Architecture should match the architecture of the Image. This decides if the Snapshot can later be
	// used with [hcloud.ArchitectureX86] or [hcloud.ArchitectureARM] servers.
	//
	// Internally this decides what server type is used for the temporary server.
	Architecture hcloud.Architecture

	// Description is an optional description that the resulting image (snapshot) will have. There is no way to
	// select images by its description, you should use Labels if you need  to identify your image later.
	Description *string

	// Labels will be added to the resulting image (snapshot). Use these to filter the image list if you
	// need to identify the image later on.
	//
	// We also always add a label `apricote.de/created-by=hcloud-image-upload` ([CreatedByLabel], [CreatedByValue]).
	Labels map[string]string

	// DebugSkipResourceCleanup will skip the cleanup of the temporary SSH Key and Server.
	DebugSkipResourceCleanup bool
}

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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