From d3d503e6e3e41949ebde2c8e3f37ec4421421ab0 Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Fri, 24 Jul 2026 17:33:14 +0200 Subject: [PATCH 1/5] docs: print deprecated Load Balancer Type information if present --- internal/cmd/loadbalancer/change_type.go | 2 ++ internal/cmd/loadbalancer/create.go | 20 ++++++++++++++------ internal/cmd/loadbalancer/texts.go | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 internal/cmd/loadbalancer/texts.go diff --git a/internal/cmd/loadbalancer/change_type.go b/internal/cmd/loadbalancer/change_type.go index 8c81a6361..6fb638227 100644 --- a/internal/cmd/loadbalancer/change_type.go +++ b/internal/cmd/loadbalancer/change_type.go @@ -44,6 +44,8 @@ var ChangeTypeCmd = base.Cmd{ return fmt.Errorf("Load Balancer Type not found: %s", loadBalancerTypeIDOrName) } + cmd.Print(deprecatedLoadBalancerTypeWarning(loadBalancerType)) + opts := hcloud.LoadBalancerChangeTypeOpts{ LoadBalancerType: loadBalancerType, } diff --git a/internal/cmd/loadbalancer/create.go b/internal/cmd/loadbalancer/create.go index 0c5f73daa..bbf35a1c9 100644 --- a/internal/cmd/loadbalancer/create.go +++ b/internal/cmd/loadbalancer/create.go @@ -52,7 +52,7 @@ var CreateCmd = base.CreateCmd[*hcloud.LoadBalancer]{ }, Run: func(s state.State, cmd *cobra.Command, _ []string) (*hcloud.LoadBalancer, any, error) { name, _ := cmd.Flags().GetString("name") - serverType, _ := cmd.Flags().GetString("type") + loadBalancerTypeName, _ := cmd.Flags().GetString("type") algorithmType, _ := cmd.Flags().GetString("algorithm-type") location, _ := cmd.Flags().GetString("location") networkZone, _ := cmd.Flags().GetString("network-zone") @@ -65,12 +65,20 @@ var CreateCmd = base.CreateCmd[*hcloud.LoadBalancer]{ return nil, nil, err } + loadBalancerType, _, err := s.Client().LoadBalancerType().Get(s, loadBalancerTypeName) + if err != nil { + return nil, nil, err + } + if loadBalancerType == nil { + return nil, nil, fmt.Errorf("Load Balancer Type not found: %s", loadBalancerTypeName) + } + + cmd.Print(deprecatedLoadBalancerTypeWarning(loadBalancerType)) + createOpts := hcloud.LoadBalancerCreateOpts{ - Name: name, - LoadBalancerType: &hcloud.LoadBalancerType{ - Name: serverType, - }, - Labels: labels, + Name: name, + LoadBalancerType: loadBalancerType, + Labels: labels, } if algorithmType != "" { createOpts.Algorithm = &hcloud.LoadBalancerAlgorithm{Type: hcloud.LoadBalancerAlgorithmType(algorithmType)} diff --git a/internal/cmd/loadbalancer/texts.go b/internal/cmd/loadbalancer/texts.go new file mode 100644 index 000000000..901242ec9 --- /dev/null +++ b/internal/cmd/loadbalancer/texts.go @@ -0,0 +1,22 @@ +package loadbalancer + +import ( + "fmt" + + "github.com/hetznercloud/hcloud-go/v2/hcloud" + "github.com/hetznercloud/hcloud-go/v2/hcloud/exp/deprecationutil" +) + +const ChangeDeprecatedLoadBalancerTypeMessage = `Existing Load Balancers of that plan will ` + + `continue to work as before and no action is required on your part. ` + + `It is possible to migrate this Load Balancer to another Load Balancer Type by using ` + + `the "hcloud load-balancer change-type" command.` + +func deprecatedLoadBalancerTypeWarning(loadBalancerType *hcloud.LoadBalancerType) string { + message, _ := deprecationutil.LoadBalancerTypeMessage(loadBalancerType) + if message == "" { + return "" + } + + return fmt.Sprintf("Attention: %s. %s\n\n", message, ChangeDeprecatedLoadBalancerTypeMessage) +} From b5db9c3c3c39abd8aeeff65375be441d125d65eb Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Fri, 24 Jul 2026 17:48:55 +0200 Subject: [PATCH 2/5] fix test --- internal/cmd/loadbalancer/create_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/cmd/loadbalancer/create_test.go b/internal/cmd/loadbalancer/create_test.go index 7be4a8c05..4c37b6b09 100644 --- a/internal/cmd/loadbalancer/create_test.go +++ b/internal/cmd/loadbalancer/create_test.go @@ -25,6 +25,9 @@ func TestCreate(t *testing.T) { cmd := loadbalancer.CreateCmd.CobraCommand(fx.State()) fx.ExpectEnsureToken() + fx.Client.LoadBalancerTypeClient.EXPECT(). + Get(gomock.Any(), "lb11"). + Return(&hcloud.LoadBalancerType{Name: "lb11"}, nil, nil) fx.Client.LoadBalancerClient.EXPECT(). Create(gomock.Any(), hcloud.LoadBalancerCreateOpts{ Name: "myLoadBalancer", @@ -88,6 +91,9 @@ func TestCreateJSON(t *testing.T) { Targets: []hcloud.LoadBalancerTarget{}, } + fx.Client.LoadBalancerTypeClient.EXPECT(). + Get(gomock.Any(), "lb11"). + Return(&hcloud.LoadBalancerType{Name: "lb11"}, nil, nil) fx.Client.LoadBalancerClient.EXPECT(). Create(gomock.Any(), hcloud.LoadBalancerCreateOpts{ Name: "myLoadBalancer", @@ -132,6 +138,9 @@ func TestCreateProtection(t *testing.T) { }, } + fx.Client.LoadBalancerTypeClient.EXPECT(). + Get(gomock.Any(), "lb11"). + Return(&hcloud.LoadBalancerType{Name: "lb11"}, nil, nil) fx.Client.LoadBalancerClient.EXPECT(). Create(gomock.Any(), hcloud.LoadBalancerCreateOpts{ Name: "myLoadBalancer", From b937a682fb5e41f08426f67d6427b64c1f6b1e7f Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 29 Jul 2026 10:10:48 +0200 Subject: [PATCH 3/5] add deprecation to lb-type list --- docs/reference/manual/hcloud_load-balancer-type_list.md | 3 ++- internal/cmd/loadbalancertype/list.go | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/reference/manual/hcloud_load-balancer-type_list.md b/docs/reference/manual/hcloud_load-balancer-type_list.md index 4f389f482..fd45781ec 100644 --- a/docs/reference/manual/hcloud_load-balancer-type_list.md +++ b/docs/reference/manual/hcloud_load-balancer-type_list.md @@ -8,9 +8,10 @@ Displays a list of Load Balancer Types. Output can be controlled with the -o flag. Use -o noheader to suppress the table header. Displayed columns and their order can be set with --o columns=description,id (see available columns below). +-o columns=deprecated,description (see available columns below). Columns: + - deprecated - description - id - max_assigned_certificates diff --git a/internal/cmd/loadbalancertype/list.go b/internal/cmd/loadbalancertype/list.go index e30267f6b..7087c97f7 100644 --- a/internal/cmd/loadbalancertype/list.go +++ b/internal/cmd/loadbalancertype/list.go @@ -5,6 +5,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/base" "github.com/hetznercloud/cli/internal/cmd/output" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" "github.com/hetznercloud/hcloud-go/v2/hcloud" @@ -27,7 +28,13 @@ var ListCmd = base.ListCmd[*hcloud.LoadBalancerType, schema.LoadBalancerType]{ OutputTable: func(t *output.Table[*hcloud.LoadBalancerType], _ hcapi2.Client) { t. - AddAllowedFields(&hcloud.LoadBalancerType{}) + AddAllowedFields(&hcloud.LoadBalancerType{}). + AddFieldFn("deprecated", func(lbType *hcloud.LoadBalancerType) string { + if !lbType.IsDeprecated() { + return "-" + } + return util.Datetime(lbType.UnavailableAfter()) + }) }, Schema: hcloud.SchemaFromLoadBalancerType, From 1cc4d2d79ee1a8772155be3c2bf69ed0fe30800f Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 29 Jul 2026 10:16:23 +0200 Subject: [PATCH 4/5] add deprecation info to describe --- internal/cmd/loadbalancertype/describe.go | 5 +++ .../cmd/loadbalancertype/describe_test.go | 35 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/internal/cmd/loadbalancertype/describe.go b/internal/cmd/loadbalancertype/describe.go index b234e8562..0a43d74a4 100644 --- a/internal/cmd/loadbalancertype/describe.go +++ b/internal/cmd/loadbalancertype/describe.go @@ -43,6 +43,11 @@ func DescribeLoadBalancerType(s state.State, loadBalancerType *hcloud.LoadBalanc fmt.Fprintf(&sb, "Max Targets:\t%d\n", loadBalancerType.MaxTargets) fmt.Fprintf(&sb, "Max assigned Certificates:\t%d\n", loadBalancerType.MaxAssignedCertificates) + if deprecationText := util.DescribeDeprecation(loadBalancerType); deprecationText != "" { + fmt.Fprintln(&sb) + fmt.Fprint(&sb, deprecationText) + } + if short { return sb.String() } diff --git a/internal/cmd/loadbalancertype/describe_test.go b/internal/cmd/loadbalancertype/describe_test.go index af58a3370..aa66b5fcb 100644 --- a/internal/cmd/loadbalancertype/describe_test.go +++ b/internal/cmd/loadbalancertype/describe_test.go @@ -1,8 +1,11 @@ package loadbalancertype_test import ( + "fmt" "testing" + "time" + "github.com/dustin/go-humanize" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -19,17 +22,23 @@ func TestDescribe(t *testing.T) { cmd := loadbalancertype.DescribeCmd.CobraCommand(fx.State()) fx.ExpectEnsureToken() + lbType := &hcloud.LoadBalancerType{ + ID: 123, + Name: "lb11", + Description: "LB11", + MaxServices: 5, + MaxConnections: 10000, + MaxTargets: 25, + MaxAssignedCertificates: 10, + DeprecatableResource: hcloud.DeprecatableResource{Deprecation: &hcloud.DeprecationInfo{ + Announced: time.Date(2036, 1, 1, 0, 0, 0, 0, time.UTC), + UnavailableAfter: time.Date(2036, 4, 1, 0, 0, 0, 0, time.UTC), + }}, + } + fx.Client.LoadBalancerTypeClient.EXPECT(). Get(gomock.Any(), "lb11"). - Return(&hcloud.LoadBalancerType{ - ID: 123, - Name: "lb11", - Description: "LB11", - MaxServices: 5, - MaxConnections: 10000, - MaxTargets: 25, - MaxAssignedCertificates: 10, - }, nil, nil) + Return(lbType, nil, nil) fx.Client.PricingClient.EXPECT(). Get(gomock.Any()). @@ -83,7 +92,7 @@ func TestDescribe(t *testing.T) { out, errOut, err := fx.Run(cmd, []string{"lb11"}) - expOut := `ID: 123 + expOut := fmt.Sprintf(`ID: 123 Name: lb11 Description: LB11 Max Services: 5 @@ -91,13 +100,17 @@ Max Connections: 10000 Max Targets: 25 Max assigned Certificates: 10 +Deprecation: + Announced: 2036-01-01 01:00:00 CET (%s) + Unavailable After: 2036-04-01 02:00:00 CEST (%s) + Pricings per Location: - Location: Falkenstein Hourly: € 1.0000 Monthly: € 2.0000 Included Traffic: 639 KiB Additional Traffic: € 3.0000 per TB -` +`, humanize.Time(lbType.DeprecationAnnounced()), humanize.Time(lbType.UnavailableAfter())) require.NoError(t, err) assert.Empty(t, errOut) From debf9ac665ec54d78e16d48136b2700fb8ec1f4d Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 29 Jul 2026 10:22:57 +0200 Subject: [PATCH 5/5] fix test --- internal/cmd/loadbalancertype/describe_test.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/internal/cmd/loadbalancertype/describe_test.go b/internal/cmd/loadbalancertype/describe_test.go index aa66b5fcb..e60cfb051 100644 --- a/internal/cmd/loadbalancertype/describe_test.go +++ b/internal/cmd/loadbalancertype/describe_test.go @@ -19,6 +19,8 @@ func TestDescribe(t *testing.T) { fx := testutil.NewFixture(t) defer fx.Finish() + time.Local = time.UTC + cmd := loadbalancertype.DescribeCmd.CobraCommand(fx.State()) fx.ExpectEnsureToken() @@ -30,10 +32,12 @@ func TestDescribe(t *testing.T) { MaxConnections: 10000, MaxTargets: 25, MaxAssignedCertificates: 10, - DeprecatableResource: hcloud.DeprecatableResource{Deprecation: &hcloud.DeprecationInfo{ - Announced: time.Date(2036, 1, 1, 0, 0, 0, 0, time.UTC), - UnavailableAfter: time.Date(2036, 4, 1, 0, 0, 0, 0, time.UTC), - }}, + DeprecatableResource: hcloud.DeprecatableResource{ + Deprecation: &hcloud.DeprecationInfo{ + Announced: time.Date(2036, 1, 1, 0, 0, 0, 0, time.UTC), + UnavailableAfter: time.Date(2036, 4, 1, 0, 0, 0, 0, time.UTC), + }, + }, } fx.Client.LoadBalancerTypeClient.EXPECT(). @@ -101,8 +105,8 @@ Max Targets: 25 Max assigned Certificates: 10 Deprecation: - Announced: 2036-01-01 01:00:00 CET (%s) - Unavailable After: 2036-04-01 02:00:00 CEST (%s) + Announced: 2036-01-01 00:00:00 UTC (%s) + Unavailable After: 2036-04-01 00:00:00 UTC (%s) Pricings per Location: - Location: Falkenstein