diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json index db709a3..2b6f241 100644 --- a/.github/release-please-manifest.json +++ b/.github/release-please-manifest.json @@ -1 +1 @@ -{".":"1.0.0","hcloudimages":"1.0.0"} +{".":"1.1.0","hcloudimages":"1.1.0"} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 124abc4..78b427c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,15 +18,15 @@ jobs: go-version-file: go.mod - name: Run golangci-lint (CLI) - uses: golangci/golangci-lint-action@v7 + uses: golangci/golangci-lint-action@v8 with: - version: v2.1.5 # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v2.1.6 # renovate: datasource=github-releases depName=golangci/golangci-lint args: --timeout 5m - name: Run golangci-lint (Lib) - uses: golangci/golangci-lint-action@v7 + uses: golangci/golangci-lint-action@v8 with: - version: v2.1.5 # renovate: datasource=github-releases depName=golangci/golangci-lint + version: v2.1.6 # renovate: datasource=github-releases depName=golangci/golangci-lint args: --timeout 5m working-directory: hcloudimages diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 5d7bc55..f8d6e93 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -19,7 +19,7 @@ jobs: - uses: ./.github/actions/setup-mdbook with: - version: v0.4.48 # renovate: datasource=github-releases depName=rust-lang/mdbook + version: v0.4.49 # renovate: datasource=github-releases depName=rust-lang/mdbook - name: Build Book working-directory: docs diff --git a/CHANGELOG.md b/CHANGELOG.md index c9c3fe4..e0ca817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [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) diff --git a/cmd/root.go b/cmd/root.go index 86cfe89..98a25d3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -9,7 +9,6 @@ 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" @@ -89,7 +88,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: backoff.ExponentialBackoffWithLimit(2, 1*time.Second, 30*time.Second)}), + hcloud.WithPollOpts(hcloud.PollOpts{BackoffFunc: hcloud.ExponentialBackoffWithOpts(hcloud.ExponentialBackoffOpts{Multiplier: 2, Base: 1 * time.Second, Cap: 30 * time.Second})}), } if os.Getenv("HCLOUD_DEBUG") != "" || verbose >= 2 { diff --git a/go.mod b/go.mod index 69de163..75c60bc 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,10 @@ module github.com/apricote/hcloud-upload-image go 1.23.0 -toolchain go1.24.2 +toolchain go1.24.3 require ( - github.com/apricote/hcloud-upload-image/hcloudimages v1.0.0 + github.com/apricote/hcloud-upload-image/hcloudimages v1.1.0 github.com/hetznercloud/hcloud-go/v2 v2.21.0 github.com/spf13/cobra v1.9.1 ) diff --git a/go.sum b/go.sum index 3d020ac..6ca002d 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/apricote/hcloud-upload-image/hcloudimages v1.0.0 h1:Gq0SSuPCiZFApGQ3SIEEQqD8btD6tRwfOxr+cky7oTo= -github.com/apricote/hcloud-upload-image/hcloudimages v1.0.0/go.mod h1:MwBmhSPlwS3S3ynOsFXPbco40Iv3udqhXKz2EXKSpVU= +github.com/apricote/hcloud-upload-image/hcloudimages v1.1.0 h1:1guW0IO2/070qbaP6zzNJJ8XsGLKPpxyE1W6fyf7MPc= +github.com/apricote/hcloud-upload-image/hcloudimages v1.1.0/go.mod h1:iJ95BaLfISZBY9X8K2Y2A5a49dI0RLjAuq+4BqlOSgA= 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= diff --git a/go.work.sum b/go.work.sum index 1f0124a..a13bce8 100644 --- a/go.work.sum +++ b/go.work.sum @@ -3,7 +3,7 @@ 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.0.0/go.mod h1:MwBmhSPlwS3S3ynOsFXPbco40Iv3udqhXKz2EXKSpVU= +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= diff --git a/hcloudimages/CHANGELOG.md b/hcloudimages/CHANGELOG.md index 076256f..3d7b6a0 100644 --- a/hcloudimages/CHANGELOG.md +++ b/hcloudimages/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [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) diff --git a/hcloudimages/backoff/backoff.go b/hcloudimages/backoff/backoff.go index 310312a..346fb8f 100644 --- a/hcloudimages/backoff/backoff.go +++ b/hcloudimages/backoff/backoff.go @@ -16,6 +16,10 @@ 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 62e218a..9652854 100644 --- a/hcloudimages/client.go +++ b/hcloudimages/client.go @@ -316,7 +316,7 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima err = control.Retry( contextlogger.New(ctx, logger.With("operation", "ssh")), - 10, + 100, // ~ 3 minutes func() error { var err error logger.DebugContext(ctx, "trying to connect to server", "ip", server.PublicNet.IPv4.IP) @@ -329,55 +329,42 @@ func (s *Client) Upload(ctx context.Context, options UploadOptions) (*hcloud.Ima } defer func() { _ = sshClient.Close() }() - // 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()) + // 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) } - 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) - } + // 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 } - switch options.ImageFormat { - case FormatRaw: - cmd += " | dd of=/dev/sda bs=4M" - case FormatQCOW2: - cmd += " > image.qcow2 && qemu-img dd -f qcow2 -O raw if=image.qcow2 of=/dev/sda bs=4M" - } - - cmd += " && 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 6: Finished writing image to disk") + output, err = sshsession.Run(sshClient, cmd, options.ImageReader) + logger.InfoContext(ctx, "# Step 7: 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) } - // 7. SSH On Server: Shutdown - logger.InfoContext(ctx, "# Step 7: Shutting down server") + // 8. SSH On Server: Shutdown + logger.InfoContext(ctx, "# Step 8: 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) } - // 8. Create Image from Server - logger.InfoContext(ctx, "# Step 8: Creating Image") + // 9. Create Image from Server + logger.InfoContext(ctx, "# Step 9: Creating Image") createImageResult, _, err := s.c.Server.CreateImage(ctx, server, &hcloud.ServerCreateImageOpts{ Type: hcloud.ImageTypeSnapshot, Description: options.Description, @@ -522,3 +509,39 @@ 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 | " + 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 4905bdf..86f8961 100644 --- a/hcloudimages/client_test.go +++ b/hcloudimages/client_test.go @@ -1,33 +1,110 @@ -package hcloudimages_test +package hcloudimages import ( - "context" - "fmt" "net/url" - - "github.com/hetznercloud/hcloud-go/v2/hcloud" - - "github.com/apricote/hcloud-upload-image/hcloudimages" + "testing" ) -func ExampleClient_Upload() { - client := hcloudimages.NewClient( - hcloud.NewClient(hcloud.WithToken("")), - ) - - imageURL, err := url.Parse("https://example.com/disk-image.raw.bz2") +func mustParseURL(s string) *url.URL { + u, err := url.Parse(s) 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) + 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 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: CompressionXZ, + }, + want: "bash -c 'set -euo pipefail && wget --no-verbose -O - \"https://example.com/image.bz2\" | xz -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) + } + }) + } } diff --git a/hcloudimages/doc_test.go b/hcloudimages/doc_test.go new file mode 100644 index 0000000..4905bdf --- /dev/null +++ b/hcloudimages/doc_test.go @@ -0,0 +1,33 @@ +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, + }) + if err != nil { + panic(err) + } + + fmt.Printf("Uploaded Image: %d", image.ID) +} diff --git a/hcloudimages/go.mod b/hcloudimages/go.mod index fbcfa83..a1f6792 100644 --- a/hcloudimages/go.mod +++ b/hcloudimages/go.mod @@ -2,12 +2,12 @@ module github.com/apricote/hcloud-upload-image/hcloudimages go 1.23.0 -toolchain go1.24.2 +toolchain go1.24.3 require ( github.com/hetznercloud/hcloud-go/v2 v2.21.0 github.com/stretchr/testify v1.10.0 - golang.org/x/crypto v0.38.0 + golang.org/x/crypto v0.39.0 ) require ( @@ -23,7 +23,7 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect golang.org/x/net v0.38.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect + golang.org/x/text v0.26.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/hcloudimages/go.sum b/hcloudimages/go.sum index 6507380..8540767 100644 --- a/hcloudimages/go.sum +++ b/hcloudimages/go.sum @@ -32,16 +32,16 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 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.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/hcloudimages/internal/control/retry.go b/hcloudimages/internal/control/retry.go index eb56721..44cfe55 100644 --- a/hcloudimages/internal/control/retry.go +++ b/hcloudimages/internal/control/retry.go @@ -8,7 +8,8 @@ import ( "context" "time" - "github.com/apricote/hcloud-upload-image/hcloudimages/backoff" + "github.com/hetznercloud/hcloud-go/v2/hcloud" + "github.com/apricote/hcloud-upload-image/hcloudimages/contextlogger" ) @@ -18,7 +19,7 @@ func Retry(ctx context.Context, maxTries int, f func() error) error { var err error - backoffFunc := backoff.ExponentialBackoffWithLimit(2, 200*time.Millisecond, 2*time.Second) + backoffFunc := hcloud.ExponentialBackoffWithOpts(hcloud.ExponentialBackoffOpts{Multiplier: 2, Base: 200 * time.Millisecond, Cap: 2 * time.Second}) for try := 0; try < maxTries; try++ { if ctx.Err() != nil { diff --git a/internal/version/version.go b/internal/version/version.go index 5d6e08f..f8df129 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.0.0" // x-release-please-version + version = "1.1.0" // x-release-please-version // versionPrerelease is a semver version pre-release identifier (https://semver.org). //