Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions docs/reference/manual/hcloud_primary-ip_create.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion docs/reference/manual/hcloud_server_create.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 27 additions & 6 deletions internal/cmd/primaryip/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ import (
var CreateCmd = base.CreateCmd[*hcloud.PrimaryIP]{
BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
cmd := &cobra.Command{
Use: "create [options] --type <ipv4|ipv6> --name <name>",
Short: "Create a Primary IP",
Use: "create [options] --type <ipv4|ipv6> --name <name>",
Short: "Create a Primary IP",
Long: `Create a Primary IP.

The --datacenter flag is deprecated. Use --location or --assignee-id instead.
See https://docs.hetzner.cloud/changelog#2025-12-16-phasing-out-datacenters`,
TraverseChildren: true,
DisableFlagsInUseLine: true,
}
Expand All @@ -28,9 +32,12 @@ var CreateCmd = base.CreateCmd[*hcloud.PrimaryIP]{
cmd.Flags().String("name", "", "Name (required)")
_ = cmd.MarkFlagRequired("name")

cmd.Flags().Int64("assignee-id", 0, "Assignee (usually a Server) to assign Primary IP to (required if 'datacenter' is not specified)")
cmd.Flags().Int64("assignee-id", 0, "Assignee (usually a Server) to assign Primary IP to")

cmd.Flags().String("location", "", "Location of Primary IP")
_ = cmd.RegisterFlagCompletionFunc("location", cmpl.SuggestCandidatesF(client.Location().Names))

cmd.Flags().String("datacenter", "", "Datacenter (ID or name) (required if 'assignee-id' is not specified)")
cmd.Flags().String("datacenter", "", "Datacenter (ID or name) (deprecated)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a snippet to the Long description that describes the deprecation of the flag and links to the changelog entry? Similar to https://github.com/hetznercloud/hcloud-cloud-controller-manager/blob/main/docs/guides/quickstart.md#quick-start

Same for all other commands.

_ = cmd.RegisterFlagCompletionFunc("datacenter", cmpl.SuggestCandidatesF(client.Datacenter().Names))

cmd.Flags().StringToString("label", nil, "User-defined labels ('key=value') (can be specified multiple times)")
Expand All @@ -40,15 +47,16 @@ var CreateCmd = base.CreateCmd[*hcloud.PrimaryIP]{

cmd.Flags().Bool("auto-delete", false, "Delete Primary IP if assigned resource is deleted (true, false)")

cmd.MarkFlagsOneRequired("assignee-id", "datacenter")
cmd.MarkFlagsMutuallyExclusive("assignee-id", "datacenter")
cmd.MarkFlagsOneRequired("assignee-id", "datacenter", "location")
cmd.MarkFlagsMutuallyExclusive("assignee-id", "datacenter", "location")
return cmd
},
Run: func(s state.State, cmd *cobra.Command, _ []string) (*hcloud.PrimaryIP, any, error) {
typ, _ := cmd.Flags().GetString("type")
name, _ := cmd.Flags().GetString("name")
assigneeID, _ := cmd.Flags().GetInt64("assignee-id")
datacenter, _ := cmd.Flags().GetString("datacenter")
locationIDOrName, _ := cmd.Flags().GetString("location")
labels, _ := cmd.Flags().GetStringToString("label")
protection, _ := cmd.Flags().GetStringSlice("enable-protection")
autoDelete, _ := cmd.Flags().GetBool("auto-delete")
Expand All @@ -71,6 +79,19 @@ var CreateCmd = base.CreateCmd[*hcloud.PrimaryIP]{
if cmd.Flags().Changed("auto-delete") {
createOpts.AutoDelete = &autoDelete
}
if cmd.Flags().Changed("location") {
location, _, err := s.Client().Location().Get(s, locationIDOrName)
if err != nil {
return nil, nil, err
}
if location == nil {
return nil, nil, fmt.Errorf("Location not found: %s", locationIDOrName)
}
createOpts.Location = location.Name
}
if cmd.Flags().Changed("datacenter") {
cmd.PrintErrln("Warning: The --datacenter flag is deprecated. Use --location or --assignee-id instead.")
}

result, _, err := s.Client().PrimaryIP().Create(s, createOpts)
if err != nil {
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/primaryip/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ func TestCreate(t *testing.T) {

out, errOut, err := fx.Run(cmd, []string{"--name=my-ip", "--type=ipv4", "--datacenter=fsn1-dc14", "--auto-delete", "--label", "foo=bar"})

expErr := "Warning: The --datacenter flag is deprecated. Use --location or --assignee-id instead.\n"

expOut := `Primary IP 1 created
IPv4: 192.168.2.1
`

require.NoError(t, err)
assert.Empty(t, errOut)
assert.Equal(t, expErr, errOut)
assert.Equal(t, expOut, out)
}

Expand Down Expand Up @@ -124,7 +126,9 @@ func TestCreateJSON(t *testing.T) {

jsonOut, out, err := fx.Run(cmd, []string{"-o=json", "--name=my-ip", "--type=ipv4", "--datacenter=fsn1-dc14", "--auto-delete", "--label", "foo=bar"})

expOut := "Primary IP 1 created\n"
expOut := `Warning: The --datacenter flag is deprecated. Use --location or --assignee-id instead.
Primary IP 1 created
`

require.NoError(t, err)
assert.Equal(t, expOut, out)
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/primaryip/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/cmd/datacenter"
"github.com/hetznercloud/cli/internal/cmd/location"
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/cli/internal/state"
Expand All @@ -26,7 +26,7 @@ var DescribeCmd = base.DescribeCmd[*hcloud.PrimaryIP]{
}
return ip, hcloud.SchemaFromPrimaryIP(ip), nil
},
PrintText: func(s state.State, _ *cobra.Command, out io.Writer, primaryIP *hcloud.PrimaryIP) error {
PrintText: func(_ state.State, _ *cobra.Command, out io.Writer, primaryIP *hcloud.PrimaryIP) error {
fmt.Fprintf(out, "ID:\t%d\n", primaryIP.ID)
fmt.Fprintf(out, "Name:\t%s\n", primaryIP.Name)
fmt.Fprintf(out, "Created:\t%s (%s)\n", util.Datetime(primaryIP.Created), humanize.Time(primaryIP.Created))
Expand Down Expand Up @@ -62,8 +62,8 @@ var DescribeCmd = base.DescribeCmd[*hcloud.PrimaryIP]{
util.DescribeLabels(out, primaryIP.Labels, "")

fmt.Fprintln(out)
fmt.Fprintf(out, "Datacenter:\n")
fmt.Fprintf(out, "%s", util.PrefixLines(datacenter.DescribeDatacenter(s.Client(), primaryIP.Datacenter, true), " "))
fmt.Fprintf(out, "Location:\n")
fmt.Fprintf(out, "%s", util.PrefixLines(location.DescribeLocation(primaryIP.Location), " "))
return nil
},
}
25 changes: 10 additions & 15 deletions internal/cmd/primaryip/describe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestDescribe(t *testing.T) {
Blocked: true,
AutoDelete: false,
AssigneeType: "server",
Datacenter: &hcloud.Datacenter{ID: 0, Location: &hcloud.Location{ID: 0}},
Location: &hcloud.Location{ID: 0},
}

fx.Client.PrimaryIPClient.EXPECT().
Expand Down Expand Up @@ -64,20 +64,15 @@ Protection:
Labels:
No labels

Datacenter:
ID: 0
Name:
Description:

Location:
ID: 0
Name:
Description:
Network Zone:
Country:
City:
Latitude: 0.000000
Longitude: 0.000000
Location:
ID: 0
Name:
Description:
Network Zone:
Country:
City:
Latitude: 0.000000
Longitude: 0.000000
`, util.Datetime(primaryIP.Created), humanize.Time(primaryIP.Created))

require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/server/change_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ var ChangeTypeCmd = base.Cmd{
return fmt.Errorf("Server Type not found: %s", serverTypeIDOrName)
}

cmd.Print(deprecatedServerTypeWarning(serverType, server.Datacenter.Location.Name))
cmd.Print(deprecatedServerTypeWarning(serverType, server.Location.Name))

keepDisk, _ := cmd.Flags().GetBool("keep-disk")
opts := hcloud.ServerChangeTypeOpts{
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/server/change_type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestChangeType(t *testing.T) {
cmd := server.ChangeTypeCmd.CobraCommand(fx.State())
fx.ExpectEnsureToken()

srv := &hcloud.Server{ID: 123, Name: "my-server", Datacenter: &hcloud.Datacenter{Location: &hcloud.Location{Name: "fsn1"}}}
srv := &hcloud.Server{ID: 123, Name: "my-server", Location: &hcloud.Location{Name: "fsn1"}}
st := &hcloud.ServerType{ID: 456, Name: "cax21", Locations: []hcloud.ServerTypeLocation{{Location: &hcloud.Location{Name: "fsn1"}}}}

fx.Client.ServerClient.EXPECT().
Expand Down Expand Up @@ -53,7 +53,7 @@ func TestChangeTypeKeepDisk(t *testing.T) {
cmd := server.ChangeTypeCmd.CobraCommand(fx.State())
fx.ExpectEnsureToken()

srv := &hcloud.Server{ID: 123, Name: "my-server", Datacenter: &hcloud.Datacenter{Location: &hcloud.Location{Name: "fsn1"}}}
srv := &hcloud.Server{ID: 123, Name: "my-server", Location: &hcloud.Location{Name: "fsn1"}}
st := &hcloud.ServerType{ID: 456, Name: "cax21", Locations: []hcloud.ServerTypeLocation{{Location: &hcloud.Location{Name: "fsn1"}}}}

fx.Client.ServerClient.EXPECT().
Expand Down
9 changes: 8 additions & 1 deletion internal/cmd/server/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ var CreateCmd = base.CreateCmd[*createResult]{
cmd := &cobra.Command{
Use: "create [options] --name <name> --type <server-type> --image <image>",
Short: "Create a Server",
Long: `Create a Server.

The --datacenter flag is deprecated. Use --location instead.
See https://docs.hetzner.cloud/changelog#2025-12-16-phasing-out-datacenters`,
}

cmd.Flags().String("name", "", "Server name (required)")
Expand All @@ -57,7 +61,7 @@ var CreateCmd = base.CreateCmd[*createResult]{
cmd.Flags().String("location", "", "Location (ID or name)")
_ = cmd.RegisterFlagCompletionFunc("location", cmpl.SuggestCandidatesF(client.Location().Names))

cmd.Flags().String("datacenter", "", "Datacenter (ID or name)")
cmd.Flags().String("datacenter", "", "Datacenter (ID or name) (deprecated)")
_ = cmd.RegisterFlagCompletionFunc("datacenter", cmpl.SuggestCandidatesF(client.Datacenter().Names))

cmd.Flags().StringSlice("ssh-key", nil, "ID or name of SSH Key to inject (can be specified multiple times)")
Expand Down Expand Up @@ -433,6 +437,8 @@ func createOptsFromFlags(
}

if datacenterIDOrName != "" {
cmd.PrintErrln("Warning: The --datacenter flag is deprecated. Use --location instead.")

var datacenter *hcloud.Datacenter
datacenter, _, err = s.Client().Datacenter().Get(s, datacenterIDOrName)
if err != nil {
Expand All @@ -444,6 +450,7 @@ func createOptsFromFlags(
}
createOpts.Datacenter = datacenter
}

if locationIDOrName != "" {
var location *hcloud.Location
location, _, err = s.Client().Location().Get(s, locationIDOrName)
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/server/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/cmd/datacenter"
"github.com/hetznercloud/cli/internal/cmd/image"
"github.com/hetznercloud/cli/internal/cmd/iso"
"github.com/hetznercloud/cli/internal/cmd/location"
"github.com/hetznercloud/cli/internal/cmd/placementgroup"
"github.com/hetznercloud/cli/internal/cmd/servertype"
"github.com/hetznercloud/cli/internal/cmd/util"
Expand Down Expand Up @@ -45,7 +45,7 @@ var DescribeCmd = base.DescribeCmd[*hcloud.Server]{
// As we already know the location the server is in, we can show the deprecation info
// of that server type in that specific location.
locationInfoIndex := slices.IndexFunc(server.ServerType.Locations, func(locInfo hcloud.ServerTypeLocation) bool {
return locInfo.Location.Name == server.Datacenter.Location.Name
return locInfo.Location.Name == server.Location.Name
})
if locationInfoIndex >= 0 {
if text := util.DescribeDeprecation(server.ServerType.Locations[locationInfoIndex]); text != "" {
Expand Down Expand Up @@ -145,8 +145,8 @@ var DescribeCmd = base.DescribeCmd[*hcloud.Server]{
}

fmt.Fprintln(out)
fmt.Fprintf(out, "Datacenter:\n")
fmt.Fprint(out, util.PrefixLines(datacenter.DescribeDatacenter(s.Client(), server.Datacenter, true), " "))
fmt.Fprintf(out, "Location:\n")
fmt.Fprint(out, util.PrefixLines(location.DescribeLocation(server.Location), " "))

fmt.Fprintln(out)
if server.BackupWindow != "" {
Expand Down
46 changes: 18 additions & 28 deletions internal/cmd/server/describe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,15 @@ func TestDescribe(t *testing.T) {
"key": "value",
},
},
Datacenter: &hcloud.Datacenter{
ID: 4,
Name: "hel1-dc2",
Location: &hcloud.Location{
ID: 3,
Name: "hel1",
Description: "Helsinki DC Park 1",
NetworkZone: "eu-central",
Country: "FI",
City: "Helsinki",
Latitude: 60.169855,
Longitude: 24.938379,
},
Description: "Helsinki 1 virtual DC 2",
Location: &hcloud.Location{
ID: 3,
Name: "hel1",
Description: "Helsinki DC Park 1",
NetworkZone: "eu-central",
Country: "FI",
City: "Helsinki",
Latitude: 60.169855,
Longitude: 24.938379,
},
IncludedTraffic: 20 * util.Tebibyte,
Protection: hcloud.ServerProtection{Delete: true, Rebuild: true},
Expand Down Expand Up @@ -149,20 +144,15 @@ Image:
Labels:
key: value

Datacenter:
ID: 4
Name: hel1-dc2
Description: Helsinki 1 virtual DC 2

Location:
ID: 3
Name: hel1
Description: Helsinki DC Park 1
Network Zone: eu-central
Country: FI
City: Helsinki
Latitude: 60.169855
Longitude: 24.938379
Location:
ID: 3
Name: hel1
Description: Helsinki DC Park 1
Network Zone: eu-central
Country: FI
City: Helsinki
Latitude: 60.169855
Longitude: 24.938379

Backup Window: Backups disabled

Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/server/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ var ListCmd = &base.ListCmd[*hcloud.Server, schema.Server]{
return server.Datacenter.Name
}).
AddFieldFn("location", func(server *hcloud.Server) string {
return server.Datacenter.Location.Name
return server.Location.Name
}).
AddFieldFn("labels", func(server *hcloud.Server) string {
return util.LabelsToString(server.Labels)
Expand Down