diff --git a/.github/actions/setup-mdbook/action.yaml b/.github/actions/setup-mdbook/action.yaml deleted file mode 100644 index 23e0665..0000000 --- a/.github/actions/setup-mdbook/action.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: "Setup mdbook" -inputs: - version: - description: "mdbook version" - -runs: - using: composite - steps: - - name: Setup mdbook - shell: bash - env: - url: https://github.com/rust-lang/mdbook/releases/download/${{ inputs.version }}/mdbook-${{ inputs.version }}-x86_64-unknown-linux-gnu.tar.gz - run: | - mkdir mdbook - curl -sSL "$url" | tar -xz --directory=./mdbook - echo `pwd`/mdbook >> $GITHUB_PATH diff --git a/.github/release-please-config.json b/.github/release-please-config.json index 393f496..f7f8d01 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -3,7 +3,7 @@ "include-component-in-tag": false, "include-v-in-tag": true, "release-type": "go", - "separate-pull-requests": true, + "group-pull-request-title-pattern": "chore(${branch}): release ${version}", "packages": { ".": { "component": "cli", @@ -16,5 +16,14 @@ "include-component-in-tag": true, "tag-separator": "/" } - } + }, + "plugins": [ + { + "type": "linked-versions", + "groupName": "repo", + "components": [ + "cli", "hcloudimages" + ] + } + ] } diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json index 0271bbd..a3e5bb7 100644 --- a/.github/release-please-manifest.json +++ b/.github/release-please-manifest.json @@ -1 +1 @@ -{".":"1.3.0","hcloudimages":"1.3.0"} +{".":"0.3.1","hcloudimages":"0.3.1"} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2feae24..126b39a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,23 +10,23 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Run golangci-lint (CLI) - uses: golangci/golangci-lint-action@v9 + uses: golangci/golangci-lint-action@v6 with: - version: v2.7.2 # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v1.62.2 # renovate: datasource=github-releases depName=golangci/golangci-lint args: --timeout 5m - name: Run golangci-lint (Lib) - uses: golangci/golangci-lint-action@v9 + uses: golangci/golangci-lint-action@v6 with: - version: v2.7.2 # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v1.62.2 # renovate: datasource=github-releases depName=golangci/golangci-lint args: --timeout 5m working-directory: hcloudimages @@ -34,10 +34,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@v5 with: go-version-file: go.mod @@ -48,10 +48,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@v5 with: go-version-file: go.mod @@ -68,10 +68,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@v5 with: go-version-file: go.mod diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml deleted file mode 100644 index aaf099d..0000000 --- a/.github/workflows/docs.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: docs -on: - push: - branches: - - main - -jobs: - deploy: - runs-on: ubuntu-latest - permissions: - contents: write # To push a branch - pages: write # To push to a GitHub Pages site - id-token: write # To update the deployment status - - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 - with: - lfs: "true" - - - uses: ./.github/actions/setup-mdbook - with: - version: v0.5.2 # renovate: datasource=github-releases depName=rust-lang/mdbook - - - name: Build Book - working-directory: docs - run: mdbook build - - - name: Setup Pages - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 - - - name: Upload artifact - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 - with: - # Upload entire repository - path: "docs/book" - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ea4e440..d842a96 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,24 +7,13 @@ on: jobs: release: - permissions: - contents: read - packages: write - runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 - - - name: Log in to the Container registry - uses: docker/login-action@6862ffc5ab2cdb4405cf318a62a6f4c066e2298b - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v6 + uses: actions/setup-go@v5 with: go-version-file: go.mod diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 474362f..5bba2d1 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -7,8 +7,7 @@ before: - ./scripts/completions.sh builds: - - id: default - env: + - env: - CGO_ENABLED=0 goos: - linux @@ -22,7 +21,7 @@ builds: - -X {{ .ModulePath }}/internal/version.versionPrerelease= archives: - - formats: [ "tar.gz" ] + - format: tar.gz # this name template makes the OS and Arch compatible with the results of `uname`. name_template: >- {{ .ProjectName }}_ @@ -34,7 +33,7 @@ archives: # use zip for windows archives format_overrides: - goos: windows - formats: [ "zip" ] + format: zip files: - README.md @@ -105,23 +104,9 @@ aurs: install -Dm644 "./completions/hcloud-upload-image.zsh" "${pkgdir}/usr/share/zsh/site-functions/_hcloud-upload-image" install -Dm644 "./completions/hcloud-upload-image.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/hcloud-upload-image.fish" -kos: - - id: container-images - build: default - repositories: - - ghcr.io/apricote - platforms: - - linux/amd64 - - linux/arm64 - base_import_paths: true - labels: - org.opencontainers.image.source: https://github.com/apricote/hcloud-upload-image - tags: - - latest - - "{{.Tag}}" snapshot: - version_template: "{{ .Version }}-dev+{{ .ShortCommit }}" + name_template: "{{ .Version }}-dev+{{ .ShortCommit }}" changelog: # Generated by release-please diff --git a/CHANGELOG.md b/CHANGELOG.md index e87b3b5..f278fae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,50 +1,5 @@ # Changelog -## [1.3.0](https://github.com/apricote/hcloud-upload-image/compare/v1.2.0...v1.3.0) (2025-12-22) - - -### Features - -* add --location flag to specify datacenter region ([#141](https://github.com/apricote/hcloud-upload-image/issues/141)) ([fcbc14a](https://github.com/apricote/hcloud-upload-image/commit/fcbc14aab6d495d2c67d653f9ea1ff56a39a8c2f)), closes [#142](https://github.com/apricote/hcloud-upload-image/issues/142) - -## [1.2.0](https://github.com/apricote/hcloud-upload-image/compare/v1.1.0...v1.2.0) (2025-11-06) - - -### Features - -* change minimum required Go version to 1.24 ([#130](https://github.com/apricote/hcloud-upload-image/issues/130)) ([5eba2d5](https://github.com/apricote/hcloud-upload-image/commit/5eba2d52fe3aafb4fd0d93403548f4c32bc2b5ac)) -* support zstd compression ([#125](https://github.com/apricote/hcloud-upload-image/issues/125)) ([37ebbce](https://github.com/apricote/hcloud-upload-image/commit/37ebbce5179997ac216af274055fc34c777b01e6)), closes [#122](https://github.com/apricote/hcloud-upload-image/issues/122) -* update default x86 server type to cx23 ([#129](https://github.com/apricote/hcloud-upload-image/issues/129)) ([a205619](https://github.com/apricote/hcloud-upload-image/commit/a20561944d0ba9485a6e10e99df15c56a688541d)) - -## [1.1.0](https://github.com/apricote/hcloud-upload-image/compare/v1.0.1...v1.1.0) (2025-05-10) - - -### Features - -* smaller snapshots by zeroing disk first ([#101](https://github.com/apricote/hcloud-upload-image/issues/101)) ([fdfb284](https://github.com/apricote/hcloud-upload-image/commit/fdfb284533d3154806b0936c08015fd5cc64b0fb)), closes [#96](https://github.com/apricote/hcloud-upload-image/issues/96) - - -### Bug Fixes - -* upload from local image generates broken command ([#98](https://github.com/apricote/hcloud-upload-image/issues/98)) ([420dcf9](https://github.com/apricote/hcloud-upload-image/commit/420dcf94c965ee470602db6c9c23c777fda91222)), closes [#97](https://github.com/apricote/hcloud-upload-image/issues/97) - -## [1.0.1](https://github.com/apricote/hcloud-upload-image/compare/v1.0.0...v1.0.1) (2025-05-09) - - -### Bug Fixes - -* timeout while waiting for SSH to become available ([#92](https://github.com/apricote/hcloud-upload-image/issues/92)) ([e490b9a](https://github.com/apricote/hcloud-upload-image/commit/e490b9a7f394e268fa1946ca51aa998c78c3d46a)) - -## [1.0.0](https://github.com/apricote/hcloud-upload-image/compare/v0.3.1...v1.0.0) (2025-05-04) - - -### Features - -* **deps:** require Go 1.23 ([#70](https://github.com/apricote/hcloud-upload-image/issues/70)) ([f3fcb62](https://github.com/apricote/hcloud-upload-image/commit/f3fcb623fc00095ab3806fa41dbcb7083c13c5df)) -* docs website ([#80](https://github.com/apricote/hcloud-upload-image/issues/80)) ([d144b85](https://github.com/apricote/hcloud-upload-image/commit/d144b85e3dfd933e8fbb09a0e6f5acacb4d05bea)) -* publish container image ([#82](https://github.com/apricote/hcloud-upload-image/issues/82)) ([91df729](https://github.com/apricote/hcloud-upload-image/commit/91df729f1cfd636355fc8338f47aefa4ab8b3b84)) -* upload qcow2 images ([#69](https://github.com/apricote/hcloud-upload-image/issues/69)) ([ac3e9dd](https://github.com/apricote/hcloud-upload-image/commit/ac3e9dd7ecd86d1538b6401c3073c7c078c40847)) - ## [0.3.1](https://github.com/apricote/hcloud-upload-image/compare/v0.3.0...v0.3.1) (2024-12-07) diff --git a/README.md b/README.md index 04a2999..c57257f 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,29 @@ -# hcloud-upload-image - -

- Quickly upload any raw disk images into your Hetzner Cloud projects! -

- -

- Badge: Documentation - Badge: Stable Release - Badge: License MIT -

+# `hcloud-upload-image` +Quickly upload any raw disk images into your [Hetzner Cloud](https://hetzner.com/cloud) projects! ## About -The [Hetzner Cloud API](https://docs.hetzner.cloud/) does not support uploading disk images directly and only provides a limited set of default images. The only option for custom disk images is to take a snapshot of an existing server’s root disk. These snapshots can then be used to create new servers. +The [Hetzner Cloud API](https://docs.hetzner.cloud/) 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 need to follow these steps: +To create a completely custom disk image, users have to follow these steps: -1. Create a server with the correct server type -2. Enable the rescue system for the server +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 the disk image to the server’s root disk +5. Write disk image to servers root disk 6. Shut down the server -7. Take a snapshot of the server’s root disk +7. Take a snapshot of the servers root disk 8. Delete the server -This is a frustratingly long process. Many users have automated it with [Packer](https://www.packer.io/) and [`packer-plugin-hcloud`](https://github.com/hetznercloud/packer-plugin-hcloud/), but Packer introduces additional complexity that can be difficult to manage. +This is an annoyingly long process. Many users have automated this with [Packer](https://www.packer.io/) & +[`packer-plugin-hcloud`](https://github.com/hetznercloud/packer-plugin-hcloud/) before, but Packer offers a lot of +additional complexity to wrap your head around. -This repository provides a simple CLI tool and Go library to streamline the process. +This repository provides a simple CLI tool & Go library to do the above. ## Getting Started @@ -40,7 +35,7 @@ We provide pre-built `deb`, `rpm` and `apk` packages. Alternatively we also prov Check out the [GitHub release artifacts](https://github.com/apricote/hcloud-upload-image/releases/latest) for all of these files and archives. -#### Arch Linux +##### Arch Linux You can get [`hcloud-upload-image-bin`](https://aur.archlinux.org/packages/hcloud-upload-image-bin) from the AUR. @@ -58,14 +53,6 @@ If you already have a recent Go toolchain installed, you can build & install the go install github.com/apricote/hcloud-upload-image@latest ``` -#### Docker - -There is a docker image published at `ghcr.io/apricote/hcloud-upload-image`. - -```shell -docker run --rm -e HCLOUD_TOKEN="" ghcr.io/apricote/hcloud-upload-image:latest -``` - #### Usage ```shell @@ -73,11 +60,10 @@ export HCLOUD_TOKEN="" hcloud-upload-image upload \ --image-url "https://example.com/disk-image-x86.raw.bz2" \ --architecture x86 \ - --compression bz2 \ - --location nbg1 # Optional: defaults to fsn1 + --compression bz2 ``` -To learn more, you can use the embedded help output or check out the [CLI help pages in this repository](docs/reference/cli/hcloud-upload-image.md).: +To learn more, you can use the embedded help output or check out the [CLI help pages in this repository](docs/cli/hcloud-upload-image.md).: ```shell hcloud-upload-image --help @@ -124,7 +110,6 @@ func main() { ImageURL: imageURL, ImageCompression: hcloudimages.CompressionBZ2, Architecture: hcloud.ArchitectureX86, - Location: &hcloud.Location{Name: "nbg1"}, // Optional: defaults to fsn1 }) if err != nil { panic(err) diff --git a/cmd/root.go b/cmd/root.go index 98a25d3..86cfe89 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" "github.com/apricote/hcloud-upload-image/hcloudimages" + "github.com/apricote/hcloud-upload-image/hcloudimages/backoff" "github.com/apricote/hcloud-upload-image/hcloudimages/contextlogger" "github.com/apricote/hcloud-upload-image/internal/ui" "github.com/apricote/hcloud-upload-image/internal/version" @@ -88,7 +89,7 @@ func initClient(cmd *cobra.Command, _ []string) { opts := []hcloud.ClientOption{ hcloud.WithToken(os.Getenv("HCLOUD_TOKEN")), hcloud.WithApplication("hcloud-upload-image", version.Version), - hcloud.WithPollOpts(hcloud.PollOpts{BackoffFunc: hcloud.ExponentialBackoffWithOpts(hcloud.ExponentialBackoffOpts{Multiplier: 2, Base: 1 * time.Second, Cap: 30 * time.Second})}), + hcloud.WithPollOpts(hcloud.PollOpts{BackoffFunc: backoff.ExponentialBackoffWithLimit(2, 1*time.Second, 30*time.Second)}), } if os.Getenv("HCLOUD_DEBUG") != "" || verbose >= 2 { diff --git a/cmd/upload.go b/cmd/upload.go index d66ff6c..9196900 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -1,9 +1,7 @@ package cmd import ( - _ "embed" "fmt" - "net/http" "net/url" "os" @@ -18,25 +16,20 @@ const ( uploadFlagImageURL = "image-url" uploadFlagImagePath = "image-path" uploadFlagCompression = "compression" - uploadFlagFormat = "format" uploadFlagArchitecture = "architecture" uploadFlagServerType = "server-type" uploadFlagDescription = "description" uploadFlagLabels = "labels" - uploadFlagLocation = "location" ) -//go:embed upload.md -var longDescription string - // uploadCmd represents the upload command var uploadCmd = &cobra.Command{ Use: "upload (--image-path= | --image-url=) --architecture=", Short: "Upload the specified disk image into your Hetzner Cloud project.", - Long: longDescription, + 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.`, 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-x86.qcow2 --architecture x86 --format qcow2`, + hcloud-upload-image upload --image-url https://examples.com/image-arm.raw --architecture arm --labels foo=bar,version=latest`, DisableAutoGenTag: true, GroupID: "primary", @@ -50,16 +43,13 @@ var uploadCmd = &cobra.Command{ 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) labels, _ := cmd.Flags().GetStringToString(uploadFlagLabels) - location, _ := cmd.Flags().GetString(uploadFlagLocation) options := hcloudimages.UploadOptions{ ImageCompression: hcloudimages.Compression(imageCompression), - ImageFormat: hcloudimages.Format(imageFormat), Description: hcloud.Ptr(description), Labels: labels, } @@ -70,26 +60,8 @@ var uploadCmd = &cobra.Command{ 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) @@ -104,10 +76,6 @@ var uploadCmd = &cobra.Command{ options.ServerType = &hcloud.ServerType{Name: serverType} } - if location != "" { - options.Location = &hcloud.Location{Name: location} - } - image, err := client.Upload(ctx, options) if err != nil { return fmt.Errorf("failed to upload the image: %w", err) @@ -127,16 +95,10 @@ func init() { uploadCmd.MarkFlagsMutuallyExclusive(uploadFlagImageURL, uploadFlagImagePath) uploadCmd.MarkFlagsOneRequired(uploadFlagImageURL, uploadFlagImagePath) - uploadCmd.Flags().String(uploadFlagCompression, "", "Type of compression that was used on the disk image [choices: bz2, xz, zstd]") + uploadCmd.Flags().String(uploadFlagCompression, "", "Type of compression that was used on the disk image [choices: bz2, xz]") _ = uploadCmd.RegisterFlagCompletionFunc( uploadFlagCompression, - cobra.FixedCompletions([]string{string(hcloudimages.CompressionBZ2), string(hcloudimages.CompressionXZ), string(hcloudimages.CompressionZSTD)}, cobra.ShellCompDirectiveNoFileComp), - ) - - uploadCmd.Flags().String(uploadFlagFormat, "", "Format of the image. [default: raw, choices: qcow2]") - _ = uploadCmd.RegisterFlagCompletionFunc( - uploadFlagFormat, - cobra.FixedCompletions([]string{string(hcloudimages.FormatQCOW2)}, cobra.ShellCompDirectiveNoFileComp), + cobra.FixedCompletions([]string{string(hcloudimages.CompressionBZ2), string(hcloudimages.CompressionXZ)}, cobra.ShellCompDirectiveNoFileComp), ) uploadCmd.Flags().String(uploadFlagArchitecture, "", "CPU architecture of the disk image [choices: x86, arm]") @@ -154,10 +116,4 @@ func init() { uploadCmd.Flags().String(uploadFlagDescription, "", "Description for the resulting image") uploadCmd.Flags().StringToString(uploadFlagLabels, map[string]string{}, "Labels for the resulting image") - - uploadCmd.Flags().String(uploadFlagLocation, "", "Datacenter location for the temporary server [default: fsn1, choices: fsn1, nbg1, hel1, ash, hil, sin]") - _ = uploadCmd.RegisterFlagCompletionFunc( - uploadFlagLocation, - cobra.FixedCompletions([]string{"fsn1", "nbg1", "hel1", "ash", "hil", "sin"}, cobra.ShellCompDirectiveNoFileComp), - ) } diff --git a/cmd/upload.md b/cmd/upload.md deleted file mode 100644 index 0d8c43c..0000000 --- a/cmd/upload.md +++ /dev/null @@ -1,12 +0,0 @@ -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. diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index b7a1b8c..0000000 --- a/docs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -book -https: diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md deleted file mode 100644 index 8f188b4..0000000 --- a/docs/SUMMARY.md +++ /dev/null @@ -1,22 +0,0 @@ -# Summary - -[Introduction](introduction.md) - -# Guides - -- [Uploading Images](guides/README.md) - - [Fedora CoreOS ↗](https://docs.fedoraproject.org/en-US/fedora-coreos/provisioning-hetzner/#_creating_a_snapshot) - - [Flatcar Container Linux ↗](https://www.flatcar.org/docs/latest/installing/cloud/hetzner/#building-the-snapshots-1) - - [Talos Linux ↗](https://www.talos.dev/v1.10/talos-guides/install/cloud-platforms/hetzner/#hcloud-upload-image) - -# Reference - -- [CLI](reference/cli/hcloud-upload-image.md) - - [`upload`](reference/cli/hcloud-upload-image_upload.md) - - [`cleanup`](reference/cli/hcloud-upload-image_cleanup.md) -- [Go Library](reference/go-library.md) - ---- - -[Changelog CLI](changelog.md) -[Changelog Go Library](changelog-hcloudimages.md) diff --git a/docs/book.toml b/docs/book.toml deleted file mode 100644 index fe0f7e1..0000000 --- a/docs/book.toml +++ /dev/null @@ -1,7 +0,0 @@ -[book] -language = "en" -src = "." -title = "hcloud-upload-image" - -[output.html] -git-repository-url = "https://github.com/apricote/hcloud-upload-image" diff --git a/docs/changelog-hcloudimages.md b/docs/changelog-hcloudimages.md deleted file mode 100644 index d492f13..0000000 --- a/docs/changelog-hcloudimages.md +++ /dev/null @@ -1,3 +0,0 @@ -# Changelog Library - -{{#include ../hcloudimages/CHANGELOG.md:2: }} diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index 76ff939..0000000 --- a/docs/changelog.md +++ /dev/null @@ -1,3 +0,0 @@ -# Changelog CLI - -{{#include ../CHANGELOG.md:2: }} diff --git a/docs/reference/cli/hcloud-upload-image.md b/docs/cli/hcloud-upload-image.md similarity index 100% rename from docs/reference/cli/hcloud-upload-image.md rename to docs/cli/hcloud-upload-image.md diff --git a/docs/reference/cli/hcloud-upload-image_cleanup.md b/docs/cli/hcloud-upload-image_cleanup.md similarity index 100% rename from docs/reference/cli/hcloud-upload-image_cleanup.md rename to docs/cli/hcloud-upload-image_cleanup.md diff --git a/docs/reference/cli/hcloud-upload-image_upload.md b/docs/cli/hcloud-upload-image_upload.md similarity index 63% rename from docs/reference/cli/hcloud-upload-image_upload.md rename to docs/cli/hcloud-upload-image_upload.md index 7ca3f31..e1dd434 100644 --- a/docs/reference/cli/hcloud-upload-image_upload.md +++ b/docs/cli/hcloud-upload-image_upload.md @@ -4,19 +4,8 @@ Upload the specified disk image into your Hetzner Cloud project. ### Synopsis -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. - +This command implements a fake "upload", by going through a real server and snapshots. +This does cost a bit of money for the server. ``` hcloud-upload-image upload (--image-path= | --image-url=) --architecture= [flags] @@ -27,21 +16,18 @@ hcloud-upload-image upload (--image-path= | --image-url=) --arc ``` 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-x86.qcow2 --architecture x86 --format qcow2 ``` ### Options ``` --architecture string CPU architecture of the disk image [choices: x86, arm] - --compression string Type of compression that was used on the disk image [choices: bz2, xz, zstd] + --compression string Type of compression that was used on the disk image [choices: bz2, xz] --description string Description for the resulting image - --format string Format of the image. [default: raw, choices: qcow2] -h, --help help for upload --image-path string Local path to the disk image that should be uploaded --image-url string Remote URL of the disk image that should be uploaded --labels stringToString Labels for the resulting image (default []) - --location string Datacenter location for the temporary server [default: fsn1, choices: fsn1, nbg1, hel1, ash, hil, sin] --server-type string Explicitly use this server type to generate the image. Mutually exclusive with --architecture. ``` diff --git a/docs/guides/README.md b/docs/guides/README.md deleted file mode 100644 index 9fc9435..0000000 --- a/docs/guides/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Uploading Images - -Check out these docs from other projects to learn how to use `hcloud-upload-image`: - -- [Fedora CoreOS ↗](https://docs.fedoraproject.org/en-US/fedora-coreos/provisioning-hetzner/#_creating_a_snapshot) -- [Flatcar Container Linux ↗](https://www.flatcar.org/docs/latest/installing/cloud/hetzner/#building-the-snapshots-1) -- [Talos Linux ↗](https://www.talos.dev/v1.10/talos-guides/install/cloud-platforms/hetzner/#hcloud-upload-image) diff --git a/docs/introduction.md b/docs/introduction.md deleted file mode 100644 index 71809aa..0000000 --- a/docs/introduction.md +++ /dev/null @@ -1,3 +0,0 @@ -# Introduction - -{{#include ../README.md:2:}} \ No newline at end of file diff --git a/docs/reference/go-library.md b/docs/reference/go-library.md deleted file mode 100644 index 46edc04..0000000 --- a/docs/reference/go-library.md +++ /dev/null @@ -1,3 +0,0 @@ -# Go Library - -You can find the documentation at [pkg.go.dev/github.com/apricote/hcloud-upload-image/hcloudimages ↗](https://pkg.go.dev/github.com/apricote/hcloud-upload-image/hcloudimages). diff --git a/go.mod b/go.mod index dfe7bed..c571bc8 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,31 @@ module github.com/apricote/hcloud-upload-image -go 1.24.0 - -toolchain go1.25.5 +go 1.22.2 require ( - github.com/apricote/hcloud-upload-image/hcloudimages v1.3.0 - github.com/hetznercloud/hcloud-go/v2 v2.34.0 - github.com/spf13/cobra v1.10.2 + github.com/apricote/hcloud-upload-image/hcloudimages v0.3.0 + github.com/hetznercloud/hcloud-go/v2 v2.17.0 + github.com/spf13/cobra v1.8.1 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/spf13/pflag v1.0.9 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/net v0.48.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect - google.golang.org/protobuf v1.36.8 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.10.0 // indirect + golang.org/x/crypto v0.30.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7a40be6..ca8fd1e 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,21 @@ -github.com/apricote/hcloud-upload-image/hcloudimages v1.3.0 h1:FVIKGSqpxdkO4+t1N8a8xu/xxc+13vHy2QaTAWICuQo= -github.com/apricote/hcloud-upload-image/hcloudimages v1.3.0/go.mod h1:NiCZ7xGoYNbWeK9L083leB7/g5oa7SAOZq405XkUSeQ= +github.com/apricote/hcloud-upload-image/hcloudimages v0.3.0 h1:POoU0nKeTq3fw7Ok/BTwJ/I3CTKhcChtn8L+Ecpba5U= +github.com/apricote/hcloud-upload-image/hcloudimages v0.3.0/go.mod h1:9W0XQVhzb9x69UBXXR0nxF0taC6s6fl0/nemDGUVrfI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/hetznercloud/hcloud-go/v2 v2.34.0 h1:mxasKipFPDPzni85xcMgwYci2PH8TalLgyPJoTlhWDA= -github.com/hetznercloud/hcloud-go/v2 v2.34.0/go.mod h1:aF9x0XYNRRQ7N4gux/4cEJeGAHcggu7sX+BBA1rv8ks= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hetznercloud/hcloud-go/v2 v2.17.0 h1:ge0w2piey9SV6XGyU/wQ6HBR24QyMbJ3wLzezplqR68= +github.com/hetznercloud/hcloud-go/v2 v2.17.0/go.mod h1:zfyZ4Orx+mPpYDzWAxXR7DHGL50nnlZ5Edzgs1o6f/s= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -26,42 +26,36 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= -github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= -github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/go.work b/go.work index 0e2f596..1b4ed3c 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,4 @@ -go 1.24.0 - -toolchain go1.25.4 +go 1.22.2 use ( . diff --git a/go.work.sum b/go.work.sum index 453c608..3e19830 100644 --- a/go.work.sum +++ b/go.work.sum @@ -3,7 +3,6 @@ github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjH github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/apricote/hcloud-upload-image/hcloudimages v1.1.0/go.mod h1:iJ95BaLfISZBY9X8K2Y2A5a49dI0RLjAuq+4BqlOSgA= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -33,20 +32,13 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/jessevdk/go-flags v1.4.1-0.20181029123624-5de817a9aa20 h1:dAOsPLhnBzIyxu0VvmnKjlNcIlgMK+erD6VRHDtweMI= github.com/jessevdk/go-flags v1.4.1-0.20181029123624-5de817a9aa20/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= -github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= github.com/jmattheis/goverter v1.4.0 h1:SrboBYMpGkj1XSgFhWwqzdP024zIa1+58YzUm+0jcBE= github.com/jmattheis/goverter v1.4.0/go.mod h1:iVIl/4qItWjWj2g3vjouGoYensJbRqDHpzlEVMHHFeY= github.com/jmattheis/goverter v1.5.1 h1:NdBYrF1V1EFQbAA1M/ZR4YVbQjxVl3L6Xupn7moF3LU= github.com/jmattheis/goverter v1.5.1/go.mod h1:iVIl/4qItWjWj2g3vjouGoYensJbRqDHpzlEVMHHFeY= -github.com/jmattheis/goverter v1.8.0 h1:P8GQ/uJEzCwpNdm5vKxaAjDDMxTpsAJZxgrXegicAW8= -github.com/jmattheis/goverter v1.8.0/go.mod h1:c8TVzpum2NThy2eJ/Wz3tyqRxzpElP2xDfoHOIDrNSQ= -github.com/jmattheis/goverter v1.9.2 h1:pBjvkhJ0F3PKMqGyHPL0yqnbTe08jjZqt/Z9ZmNKtTQ= -github.com/jmattheis/goverter v1.9.2/go.mod h1:1n3q6zf7j58tXcRWHbLFxK2Jk8WQVzr0d3nuaCcRqeg= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -73,8 +65,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/vburenin/ifacemaker v1.2.1 h1:3Vq8B/bfBgjWTkv+jDg4dVL1KHt3k1K4lO7XRxYA2sk= github.com/vburenin/ifacemaker v1.2.1/go.mod h1:5WqrzX2aD7/hi+okBjcaEQJMg4lDGrpuEX3B8L4Wgrs= -github.com/vburenin/ifacemaker v1.3.0 h1:X5//v/1tyORf5157wLATgP1wgquW3FUW91/OGHLRqGo= -github.com/vburenin/ifacemaker v1.3.0/go.mod h1:SxTD9m+6uBQyhd0aohV7R4iirO+l9mEoTn4nSe67vMs= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= @@ -85,22 +75,13 @@ golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= @@ -111,23 +92,12 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= -golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= @@ -135,10 +105,6 @@ golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= -golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/hcloudimages/CHANGELOG.md b/hcloudimages/CHANGELOG.md index e5d6069..f5711d3 100644 --- a/hcloudimages/CHANGELOG.md +++ b/hcloudimages/CHANGELOG.md @@ -1,47 +1,5 @@ # Changelog -## [1.3.0](https://github.com/apricote/hcloud-upload-image/compare/hcloudimages/v1.2.0...hcloudimages/v1.3.0) (2025-12-22) - - -### Features - -* add --location flag to specify datacenter region ([#141](https://github.com/apricote/hcloud-upload-image/issues/141)) ([fcbc14a](https://github.com/apricote/hcloud-upload-image/commit/fcbc14aab6d495d2c67d653f9ea1ff56a39a8c2f)), closes [#142](https://github.com/apricote/hcloud-upload-image/issues/142) - -## [1.2.0](https://github.com/apricote/hcloud-upload-image/compare/hcloudimages/v1.1.0...hcloudimages/v1.2.0) (2025-11-06) - - -### Features - -* change minimum required Go version to 1.24 ([#130](https://github.com/apricote/hcloud-upload-image/issues/130)) ([5eba2d5](https://github.com/apricote/hcloud-upload-image/commit/5eba2d52fe3aafb4fd0d93403548f4c32bc2b5ac)) -* support zstd compression ([#125](https://github.com/apricote/hcloud-upload-image/issues/125)) ([37ebbce](https://github.com/apricote/hcloud-upload-image/commit/37ebbce5179997ac216af274055fc34c777b01e6)), closes [#122](https://github.com/apricote/hcloud-upload-image/issues/122) -* update default x86 server type to cx23 ([#129](https://github.com/apricote/hcloud-upload-image/issues/129)) ([a205619](https://github.com/apricote/hcloud-upload-image/commit/a20561944d0ba9485a6e10e99df15c56a688541d)) - -## [1.1.0](https://github.com/apricote/hcloud-upload-image/compare/hcloudimages/v1.0.1...hcloudimages/v1.1.0) (2025-05-10) - - -### Features - -* smaller snapshots by zeroing disk first ([#101](https://github.com/apricote/hcloud-upload-image/issues/101)) ([fdfb284](https://github.com/apricote/hcloud-upload-image/commit/fdfb284533d3154806b0936c08015fd5cc64b0fb)), closes [#96](https://github.com/apricote/hcloud-upload-image/issues/96) - - -### Bug Fixes - -* upload from local image generates broken command ([#98](https://github.com/apricote/hcloud-upload-image/issues/98)) ([420dcf9](https://github.com/apricote/hcloud-upload-image/commit/420dcf94c965ee470602db6c9c23c777fda91222)), closes [#97](https://github.com/apricote/hcloud-upload-image/issues/97) - -## [1.0.1](https://github.com/apricote/hcloud-upload-image/compare/hcloudimages/v1.0.0...hcloudimages/v1.0.1) (2025-05-09) - - -### Bug Fixes - -* timeout while waiting for SSH to become available ([#92](https://github.com/apricote/hcloud-upload-image/issues/92)) ([e490b9a](https://github.com/apricote/hcloud-upload-image/commit/e490b9a7f394e268fa1946ca51aa998c78c3d46a)) - -## [1.0.0](https://github.com/apricote/hcloud-upload-image/compare/hcloudimages/v0.3.1...hcloudimages/v1.0.0) (2025-05-04) - - -### Features - -* upload qcow2 images ([#69](https://github.com/apricote/hcloud-upload-image/issues/69)) ([ac3e9dd](https://github.com/apricote/hcloud-upload-image/commit/ac3e9dd7ecd86d1538b6401c3073c7c078c40847)) - ## [0.3.1](https://github.com/apricote/hcloud-upload-image/compare/hcloudimages/v0.3.0...hcloudimages/v0.3.1) (2024-12-07) diff --git a/hcloudimages/backoff/backoff.go b/hcloudimages/backoff/backoff.go index 346fb8f..310312a 100644 --- a/hcloudimages/backoff/backoff.go +++ b/hcloudimages/backoff/backoff.go @@ -16,10 +16,6 @@ import ( // It uses the formula: // // min(b^retries * d, limit) -// -// This function has a known overflow issue and should not be used anymore. -// -// Deprecated: Use BackoffFuncWithOpts from github.com/hetznercloud/hcloud-go/v2/hcloud instead. func ExponentialBackoffWithLimit(b float64, d time.Duration, limit time.Duration) hcloud.BackoffFunc { return func(retries int) time.Duration { current := time.Duration(math.Pow(b, float64(retries))) * d diff --git a/hcloudimages/client.go b/hcloudimages/client.go index cf2f4e7..9c6db28 100644 --- a/hcloudimages/client.go +++ b/hcloudimages/client.go @@ -34,7 +34,7 @@ var ( } serverTypePerArchitecture = map[hcloud.Architecture]*hcloud.ServerType{ - hcloud.ArchitectureX86: {Name: "cx23"}, + hcloud.ArchitectureX86: {Name: "cx22"}, hcloud.ArchitectureARM: {Name: "cax11"}, } @@ -43,10 +43,6 @@ var ( defaultRescueType = hcloud.ServerRescueTypeLinux64 defaultSSHDialTimeout = 1 * time.Minute - - // Size observed on x86, 2025-05-03, no idea if that changes. - // Might be able to extends this to more of the available memory. - rescueSystemRootDiskSizeMB int64 = 960 ) type UploadOptions struct { @@ -60,14 +56,10 @@ type UploadOptions struct { // set to anything else, the file will be decompressed before written to the disk. ImageCompression Compression - ImageFormat Format - - // Can be optionally set to make the client validate that the image can be written to the server. - ImageSize int64 - // Possible future additions: // ImageSignatureVerification // ImageLocalPath + // ImageType (RawDiskImage, ISO, qcow2, ...) // Architecture should match the architecture of the Image. This decides if the Snapshot can later be // used with [hcloud.ArchitectureX86] or [hcloud.ArchitectureARM] servers. @@ -94,10 +86,6 @@ type UploadOptions struct { // We also always add a label `apricote.de/created-by=hcloud-image-upload` ([CreatedByLabel], [CreatedByValue]). Labels map[string]string - // Location is the datacenter location for the temporary server. - // Defaults to fsn1 if not specified. - Location *hcloud.Location - // DebugSkipResourceCleanup will skip the cleanup of the temporary SSH Key and Server. DebugSkipResourceCleanup bool } @@ -108,23 +96,9 @@ const ( CompressionNone Compression = "" CompressionBZ2 Compression = "bz2" CompressionXZ Compression = "xz" - CompressionZSTD Compression = "zstd" // Possible future additions: - // zip -) - -type Format string - -const ( - FormatRaw Format = "" - - // FormatQCOW2 allows to upload images in the qcow2 format directly. - // - // The qcow2 image must fit on the disk available in the rescue system. "qemu-img dd", which is used to convert - // qcow2 to raw, requires a file as an input. If [UploadOption.ImageSize] is set and FormatQCOW2 is used, there is a - // warning message displayed if there is a high probability of issues. - FormatQCOW2 Format = "qcow2" + // zip,zstd ) // NewClient instantiates a new client. It requires a working [*hcloud.Client] to interact with the Hetzner Cloud API. @@ -160,19 +134,6 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima resourceName := resourcePrefix + id labels := labelutil.Merge(DefaultLabels, options.Labels) - // 0. Validations - if options.ImageFormat == FormatQCOW2 && options.ImageSize > 0 { - if options.ImageSize > rescueSystemRootDiskSizeMB*1024*1024 { - // Just a warning, because the size might change with time. - // Alternatively one could add an override flag for the check and make this an error. - logger.WarnContext(ctx, - fmt.Sprintf("image must be smaller than %d MB (rescue system root disk) for qcow2", rescueSystemRootDiskSizeMB), - "maximum-size", rescueSystemRootDiskSizeMB, - "actual-size", options.ImageSize/(1024*1024), - ) - } - } - // 1. Create SSH Key logger.InfoContext(ctx, "# Step 1: Generating SSH Key") privateKey, publicKey, err := sshutil.GenerateKeyPair() @@ -218,14 +179,9 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima } } - location := defaultLocation - if options.Location != nil { - location = options.Location - } - logger.DebugContext(ctx, "creating server with config", "image", defaultImage.Name, - "location", location.Name, + "location", defaultLocation.Name, "serverType", serverType.Name, ) serverCreateResult, _, err := s.c.Server.Create(ctx, hcloud.ServerCreateOpts{ @@ -239,7 +195,7 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima StartAfterCreate: hcloud.Ptr(false), // Image will never be booted, we only boot into rescue system Image: defaultImage, - Location: location, + Location: defaultLocation, Labels: labels, }) if err != nil { @@ -326,7 +282,7 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima err = control.Retry( contextlogger.New(ctx, logger.With("operation", "ssh")), - 100, // ~ 3 minutes + 10, func() error { var err error logger.DebugContext(ctx, "trying to connect to server", "ip", server.PublicNet.IPv4.IP) @@ -337,44 +293,50 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima if err != nil { return nil, fmt.Errorf("failed to ssh into temporary server: %w", err) } - defer func() { _ = sshClient.Close() }() + defer sshClient.Close() - // 6. Wipe existing disk, to avoid storing any bytes from it in the snapshot - logger.InfoContext(ctx, "# Step 6: Cleaning existing disk") - - output, err := sshsession.Run(sshClient, "blkdiscard /dev/sda", nil) - logger.DebugContext(ctx, string(output)) - if err != nil { - return nil, fmt.Errorf("failed to clean existing disk: %w", err) + // 6. SSH On Server: Download Image, Decompress, Write to Root Disk + logger.InfoContext(ctx, "# Step 6: Downloading image and writing to disk") + cmd := "" + if options.ImageURL != nil { + cmd += fmt.Sprintf("wget --no-verbose -O - %q | ", options.ImageURL.String()) } - // 7. SSH On Server: Download Image, Decompress, Write to Root Disk - logger.InfoContext(ctx, "# Step 7: Downloading image and writing to disk") - - cmd, err := assembleCommand(options) - if err != nil { - return nil, err + if options.ImageCompression != CompressionNone { + switch options.ImageCompression { + case CompressionBZ2: + cmd += "bzip2 -cd | " + case CompressionXZ: + cmd += "xz -cd | " + default: + return nil, fmt.Errorf("unknown compression: %q", options.ImageCompression) + } } + cmd += "dd of=/dev/sda bs=4M && sync" + + // Make sure that we fail early, ie. if the image url does not work. + // the pipefail does not work correctly without wrapping in bash. + cmd = fmt.Sprintf("bash -c 'set -euo pipefail && %s'", cmd) logger.DebugContext(ctx, "running download, decompress and write to disk command", "cmd", cmd) - output, err = sshsession.Run(sshClient, cmd, options.ImageReader) - logger.InfoContext(ctx, "# Step 7: Finished writing image to disk") + output, err := sshsession.Run(sshClient, cmd, options.ImageReader) + logger.InfoContext(ctx, "# Step 6: Finished writing image to disk") logger.DebugContext(ctx, string(output)) if err != nil { return nil, fmt.Errorf("failed to download and write the image: %w", err) } - // 8. SSH On Server: Shutdown - logger.InfoContext(ctx, "# Step 8: Shutting down server") + // 7. SSH On Server: Shutdown + logger.InfoContext(ctx, "# Step 7: Shutting down server") _, err = sshsession.Run(sshClient, "shutdown now", nil) if err != nil { // TODO Verify if shutdown error, otherwise return logger.WarnContext(ctx, "shutdown returned error", "err", err) } - // 9. Create Image from Server - logger.InfoContext(ctx, "# Step 9: Creating Image") + // 8. Create Image from Server + logger.InfoContext(ctx, "# Step 8: Creating Image") createImageResult, _, err := s.c.Server.CreateImage(ctx, server, &hcloud.ServerCreateImageOpts{ Type: hcloud.ImageTypeSnapshot, Description: options.Description, @@ -519,41 +481,3 @@ func (s *Client) cleanupTempSSHKeys(ctx context.Context, logger *slog.Logger, se return nil } - -func assembleCommand(options UploadOptions) (string, error) { - // Make sure that we fail early, ie. if the image url does not work - cmd := "set -euo pipefail && " - - if options.ImageURL != nil { - cmd += fmt.Sprintf("wget --no-verbose -O - %q | ", options.ImageURL.String()) - } - - if options.ImageCompression != CompressionNone { - switch options.ImageCompression { - case CompressionBZ2: - cmd += "bzip2 -cd | " - case CompressionXZ: - cmd += "xz -cd | " - case CompressionZSTD: - cmd += "zstd -cd | " - default: - return "", fmt.Errorf("unknown compression: %q", options.ImageCompression) - } - } - - switch options.ImageFormat { - case FormatRaw: - cmd += "dd of=/dev/sda bs=4M" - case FormatQCOW2: - cmd += "tee image.qcow2 > /dev/null && qemu-img dd -f qcow2 -O raw if=image.qcow2 of=/dev/sda bs=4M" - default: - return "", fmt.Errorf("unknown format: %q", options.ImageFormat) - } - - cmd += " && sync" - - // the pipefail does not work correctly without wrapping in bash. - cmd = fmt.Sprintf("bash -c '%s'", cmd) - - return cmd, nil -} diff --git a/hcloudimages/client_test.go b/hcloudimages/client_test.go index d1d1d33..4905bdf 100644 --- a/hcloudimages/client_test.go +++ b/hcloudimages/client_test.go @@ -1,125 +1,33 @@ -package hcloudimages +package hcloudimages_test import ( + "context" + "fmt" "net/url" - "testing" + + "github.com/hetznercloud/hcloud-go/v2/hcloud" + + "github.com/apricote/hcloud-upload-image/hcloudimages" ) -func mustParseURL(s string) *url.URL { - u, err := url.Parse(s) +func ExampleClient_Upload() { + client := hcloudimages.NewClient( + hcloud.NewClient(hcloud.WithToken("")), + ) + + imageURL, err := url.Parse("https://example.com/disk-image.raw.bz2") if err != nil { panic(err) } - return u -} - -func TestAssembleCommand(t *testing.T) { - tests := []struct { - name string - options UploadOptions - want string - wantErr bool - }{ - { - name: "local raw", - options: UploadOptions{}, - want: "bash -c 'set -euo pipefail && dd of=/dev/sda bs=4M && sync'", - }, - { - name: "remote raw", - options: UploadOptions{ - ImageURL: mustParseURL("https://example.com/image.xz"), - }, - want: "bash -c 'set -euo pipefail && wget --no-verbose -O - \"https://example.com/image.xz\" | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "local xz", - options: UploadOptions{ - ImageCompression: CompressionXZ, - }, - want: "bash -c 'set -euo pipefail && xz -cd | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "remote xz", - options: UploadOptions{ - ImageURL: mustParseURL("https://example.com/image.xz"), - ImageCompression: CompressionXZ, - }, - want: "bash -c 'set -euo pipefail && wget --no-verbose -O - \"https://example.com/image.xz\" | xz -cd | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "local zstd", - options: UploadOptions{ - ImageCompression: CompressionZSTD, - }, - want: "bash -c 'set -euo pipefail && zstd -cd | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "remote zstd", - options: UploadOptions{ - ImageURL: mustParseURL("https://example.com/image.zst"), - ImageCompression: CompressionZSTD, - }, - want: "bash -c 'set -euo pipefail && wget --no-verbose -O - \"https://example.com/image.zst\" | zstd -cd | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "local bz2", - options: UploadOptions{ - ImageCompression: CompressionBZ2, - }, - want: "bash -c 'set -euo pipefail && bzip2 -cd | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "remote bz2", - options: UploadOptions{ - ImageURL: mustParseURL("https://example.com/image.bz2"), - ImageCompression: CompressionBZ2, - }, - want: "bash -c 'set -euo pipefail && wget --no-verbose -O - \"https://example.com/image.bz2\" | bzip2 -cd | dd of=/dev/sda bs=4M && sync'", - }, - { - name: "local qcow2", - options: UploadOptions{ - ImageFormat: FormatQCOW2, - }, - want: "bash -c 'set -euo pipefail && tee image.qcow2 > /dev/null && qemu-img dd -f qcow2 -O raw if=image.qcow2 of=/dev/sda bs=4M && sync'", - }, - { - name: "remote qcow2", - options: UploadOptions{ - ImageURL: mustParseURL("https://example.com/image.qcow2"), - ImageFormat: FormatQCOW2, - }, - want: "bash -c 'set -euo pipefail && wget --no-verbose -O - \"https://example.com/image.qcow2\" | tee image.qcow2 > /dev/null && qemu-img dd -f qcow2 -O raw if=image.qcow2 of=/dev/sda bs=4M && sync'", - }, - - { - name: "unknown compression", - options: UploadOptions{ - ImageCompression: "noodle", - }, - wantErr: true, - }, - - { - name: "unknown format", - options: UploadOptions{ - ImageFormat: "poodle", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := assembleCommand(tt.options) - if (err != nil) != tt.wantErr { - t.Errorf("assembleCommand() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("assembleCommand() got = %v, want %v", got, tt.want) - } - }) + 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) } diff --git a/hcloudimages/doc_test.go b/hcloudimages/doc_test.go deleted file mode 100644 index e07c720..0000000 --- a/hcloudimages/doc_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package hcloudimages_test - -import ( - "context" - "fmt" - "net/url" - - "github.com/hetznercloud/hcloud-go/v2/hcloud" - - "github.com/apricote/hcloud-upload-image/hcloudimages" -) - -func ExampleClient_Upload() { - client := hcloudimages.NewClient( - hcloud.NewClient(hcloud.WithToken("")), - ) - - 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, - Location: &hcloud.Location{Name: "nbg1"}, // Optional: defaults to fsn1 - }) - if err != nil { - panic(err) - } - - fmt.Printf("Uploaded Image: %d", image.ID) -} diff --git a/hcloudimages/go.mod b/hcloudimages/go.mod index 27e05fd..060bd1e 100644 --- a/hcloudimages/go.mod +++ b/hcloudimages/go.mod @@ -1,29 +1,27 @@ module github.com/apricote/hcloud-upload-image/hcloudimages -go 1.24.0 - -toolchain go1.25.5 +go 1.22.2 require ( - github.com/hetznercloud/hcloud-go/v2 v2.34.0 - github.com/stretchr/testify v1.11.1 - golang.org/x/crypto v0.46.0 + github.com/hetznercloud/hcloud-go/v2 v2.17.0 + github.com/stretchr/testify v1.10.0 + golang.org/x/crypto v0.30.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.48.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect - google.golang.org/protobuf v1.36.8 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/hcloudimages/go.sum b/hcloudimages/go.sum index 231bc23..eb71b61 100644 --- a/hcloudimages/go.sum +++ b/hcloudimages/go.sum @@ -4,12 +4,12 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/hetznercloud/hcloud-go/v2 v2.34.0 h1:mxasKipFPDPzni85xcMgwYci2PH8TalLgyPJoTlhWDA= -github.com/hetznercloud/hcloud-go/v2 v2.34.0/go.mod h1:aF9x0XYNRRQ7N4gux/4cEJeGAHcggu7sX+BBA1rv8ks= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hetznercloud/hcloud-go/v2 v2.17.0 h1:ge0w2piey9SV6XGyU/wQ6HBR24QyMbJ3wLzezplqR68= +github.com/hetznercloud/hcloud-go/v2 v2.17.0/go.mod h1:zfyZ4Orx+mPpYDzWAxXR7DHGL50nnlZ5Edzgs1o6f/s= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -20,34 +20,30 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/hcloudimages/internal/control/retry.go b/hcloudimages/internal/control/retry.go index 44cfe55..d053aee 100644 --- a/hcloudimages/internal/control/retry.go +++ b/hcloudimages/internal/control/retry.go @@ -8,8 +8,7 @@ import ( "context" "time" - "github.com/hetznercloud/hcloud-go/v2/hcloud" - + "github.com/apricote/hcloud-upload-image/hcloudimages/backoff" "github.com/apricote/hcloud-upload-image/hcloudimages/contextlogger" ) @@ -19,7 +18,7 @@ func Retry(ctx context.Context, maxTries int, f func() error) error { var err error - backoffFunc := hcloud.ExponentialBackoffWithOpts(hcloud.ExponentialBackoffOpts{Multiplier: 2, Base: 200 * time.Millisecond, Cap: 2 * time.Second}) + backoffFunc := backoff.ExponentialBackoffWithLimit(2, 1*time.Second, 30*time.Second) for try := 0; try < maxTries; try++ { if ctx.Err() != nil { diff --git a/hcloudimages/internal/sshsession/session.go b/hcloudimages/internal/sshsession/session.go index f725251..4306ce1 100644 --- a/hcloudimages/internal/sshsession/session.go +++ b/hcloudimages/internal/sshsession/session.go @@ -12,7 +12,7 @@ func Run(client *ssh.Client, cmd string, stdin io.Reader) ([]byte, error) { if err != nil { return nil, err } - defer func() { _ = sess.Close() }() + defer sess.Close() if stdin != nil { sess.Stdin = stdin diff --git a/internal/version/version.go b/internal/version/version.go index a4f584f..780018a 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -2,7 +2,7 @@ package version var ( // version is a semver version (https://semver.org). - version = "1.3.0" // x-release-please-version + version = "0.3.1" // x-release-please-version // versionPrerelease is a semver version pre-release identifier (https://semver.org). // diff --git a/renovate.json b/renovate.json index ada450e..d970352 100644 --- a/renovate.json +++ b/renovate.json @@ -11,18 +11,12 @@ "gomodTidy", "gomodUpdateImportPaths" ], - "goGetDirs": [ - "./...", - "./hcloudimages/..." - ], "customManagers": [ { "customType": "regex", - "managerFilePatterns": [ - "/^\\.github\\/(?:workflows|actions)\\/.+\\.ya?ml$/" - ], + "fileMatch": ["^\\.github\\/(?:workflows|actions)\\/.+\\.ya?ml$"], "matchStrings": [ - "(?:version|VERSION): (?.+) # renovate: datasource=(?[a-z-]+) depName=(?.+)(?: packageName=(?.+))?(?: versioning=(?[a-z-]+))?" + "(?:version|VERSION): (?.+) # renovate: datasource=(?[a-z-]+) depName=(?.+)(?: lookupName=(?.+))?(?: versioning=(?[a-z-]+))?" ] } ] diff --git a/scripts/cli-help-pages.go b/scripts/cli-help-pages.go index 527b04a..778a19b 100644 --- a/scripts/cli-help-pages.go +++ b/scripts/cli-help-pages.go @@ -11,7 +11,7 @@ import ( func run() error { // Define the directory where the docs will be generated - dir := "docs/reference/cli" + dir := "docs/cli" // Ensure the directory exists if err := os.MkdirAll(dir, 0755); err != nil {