mirror of
https://github.com/apricote/hcloud-upload-image.git
synced 2026-01-13 21:31:03 +00:00
feat: upload qcow2 images
It is now possible to upload qcow2 images directly. These images will be converted to raw disk images directly on the cloud server. In the CLI you can use the new `--format=qcow2` flag to upload qcow2 images. In the library you can set `UploadOptions.ImageFormat` to `FormatQCOW2`. Because of the underlying process, qcow2 images need to be written to a file first. This limits their size to 960 MB at the moment. The CLI automatically checks the file size (if possible) and shows a warning if this limit would be triggered. The library accepts an input with the file size and logs a warning if the limit would be triggered.
This commit is contained in:
parent
021787a9c3
commit
064c91cdc3
5 changed files with 110 additions and 10 deletions
|
|
@ -1,7 +1,9 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
|
|
@ -16,20 +18,24 @@ const (
|
|||
uploadFlagImageURL = "image-url"
|
||||
uploadFlagImagePath = "image-path"
|
||||
uploadFlagCompression = "compression"
|
||||
uploadFlagFormat = "format"
|
||||
uploadFlagArchitecture = "architecture"
|
||||
uploadFlagServerType = "server-type"
|
||||
uploadFlagDescription = "description"
|
||||
uploadFlagLabels = "labels"
|
||||
)
|
||||
|
||||
//go:embed upload.md
|
||||
var longDescription string
|
||||
|
||||
// uploadCmd represents the upload command
|
||||
var uploadCmd = &cobra.Command{
|
||||
Use: "upload (--image-path=<local-path> | --image-url=<url>) --architecture=<x86|arm>",
|
||||
Short: "Upload the specified disk image into your Hetzner Cloud project.",
|
||||
Long: `This command implements a fake "upload", by going through a real server and snapshots.
|
||||
This does cost a bit of money for the server.`,
|
||||
Long: longDescription,
|
||||
Example: ` hcloud-upload-image upload --image-path /home/you/images/custom-linux-image-x86.bz2 --architecture x86 --compression bz2 --description "My super duper custom linux"
|
||||
hcloud-upload-image upload --image-url https://examples.com/image-arm.raw --architecture arm --labels foo=bar,version=latest`,
|
||||
hcloud-upload-image upload --image-url https://examples.com/image-arm.raw --architecture arm --labels foo=bar,version=latest
|
||||
hcloud-upload-image upload --image-url https://examples.com/image-x86.qcow2 --architecture x86 --format qcow2`,
|
||||
DisableAutoGenTag: true,
|
||||
|
||||
GroupID: "primary",
|
||||
|
|
@ -43,6 +49,7 @@ This does cost a bit of money for the server.`,
|
|||
imageURLString, _ := cmd.Flags().GetString(uploadFlagImageURL)
|
||||
imagePathString, _ := cmd.Flags().GetString(uploadFlagImagePath)
|
||||
imageCompression, _ := cmd.Flags().GetString(uploadFlagCompression)
|
||||
imageFormat, _ := cmd.Flags().GetString(uploadFlagFormat)
|
||||
architecture, _ := cmd.Flags().GetString(uploadFlagArchitecture)
|
||||
serverType, _ := cmd.Flags().GetString(uploadFlagServerType)
|
||||
description, _ := cmd.Flags().GetString(uploadFlagDescription)
|
||||
|
|
@ -50,6 +57,7 @@ This does cost a bit of money for the server.`,
|
|||
|
||||
options := hcloudimages.UploadOptions{
|
||||
ImageCompression: hcloudimages.Compression(imageCompression),
|
||||
ImageFormat: hcloudimages.Format(imageFormat),
|
||||
Description: hcloud.Ptr(description),
|
||||
Labels: labels,
|
||||
}
|
||||
|
|
@ -60,8 +68,26 @@ This does cost a bit of money for the server.`,
|
|||
return fmt.Errorf("unable to parse url from --%s=%q: %w", uploadFlagImageURL, imageURLString, err)
|
||||
}
|
||||
|
||||
// Check for image size
|
||||
resp, err := http.Head(imageURL.String())
|
||||
switch {
|
||||
case err != nil:
|
||||
logger.DebugContext(ctx, "failed to check for file size, error on request", "err", err)
|
||||
case resp.ContentLength == -1:
|
||||
logger.DebugContext(ctx, "failed to check for file size, server did not set the Content-Length", "err", err)
|
||||
default:
|
||||
options.ImageSize = resp.ContentLength
|
||||
}
|
||||
|
||||
options.ImageURL = imageURL
|
||||
} else if imagePathString != "" {
|
||||
stat, err := os.Stat(imagePathString)
|
||||
if err != nil {
|
||||
logger.DebugContext(ctx, "failed to check for file size, error on stat", "err", err)
|
||||
} else {
|
||||
options.ImageSize = stat.Size()
|
||||
}
|
||||
|
||||
imageFile, err := os.Open(imagePathString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read file from --%s=%q: %w", uploadFlagImagePath, imagePathString, err)
|
||||
|
|
@ -101,6 +127,12 @@ func init() {
|
|||
cobra.FixedCompletions([]string{string(hcloudimages.CompressionBZ2), string(hcloudimages.CompressionXZ)}, cobra.ShellCompDirectiveNoFileComp),
|
||||
)
|
||||
|
||||
uploadCmd.Flags().String(uploadFlagFormat, "", "Format of the image. [choices: qcow2]")
|
||||
_ = uploadCmd.RegisterFlagCompletionFunc(
|
||||
uploadFlagFormat,
|
||||
cobra.FixedCompletions([]string{string(hcloudimages.FormatQCOW2)}, cobra.ShellCompDirectiveNoFileComp),
|
||||
)
|
||||
|
||||
uploadCmd.Flags().String(uploadFlagArchitecture, "", "CPU architecture of the disk image [choices: x86, arm]")
|
||||
_ = uploadCmd.RegisterFlagCompletionFunc(
|
||||
uploadFlagArchitecture,
|
||||
|
|
|
|||
12
cmd/upload.md
Normal file
12
cmd/upload.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
This command implements a fake "upload", by going through a real server and
|
||||
snapshots. This does cost a bit of money for the server.
|
||||
|
||||
#### Image Size
|
||||
|
||||
The image size for raw disk images is only limited by the servers root disk.
|
||||
|
||||
The image size for qcow2 images is limited to the rescue systems root disk.
|
||||
This is currently a memory-backed file system with **960 MB** of space. A qcow2
|
||||
image not be larger than this size, or the process will error. There is a
|
||||
warning being logged if hcloud-upload-image can detect that your file is larger
|
||||
than this size.
|
||||
Loading…
Add table
Add a link
Reference in a new issue