Skip to content

Commit

Permalink
feat: add --enable-protection flag to "create" commands (#567)
Browse files Browse the repository at this point in the history
As requested in #488
  • Loading branch information
phm07 committed Oct 18, 2023
1 parent 09f1a4d commit e313e69
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 43 deletions.
21 changes: 15 additions & 6 deletions internal/cmd/floatingip/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ var CreateCommand = base.Cmd{

cmd.Flags().StringToString("label", nil, "User-defined labels ('key=value') (can be specified multiple times)")

cmd.Flags().StringSlice("enable-protection", []string{}, "Enable protection (delete) (default: none)")
cmd.RegisterFlagCompletionFunc("enable-protection", cmpl.SuggestCandidates("delete"))

return cmd
},
Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
Expand All @@ -56,17 +59,23 @@ var CreateCommand = base.Cmd{
description, _ := cmd.Flags().GetString("description")
serverNameOrID, _ := cmd.Flags().GetString("server")
labels, _ := cmd.Flags().GetStringToString("label")
protection, _ := cmd.Flags().GetStringSlice("enable-protection")

protectionOps, err := getChangeProtectionOpts(true, protection)
if err != nil {
return err
}

opts := hcloud.FloatingIPCreateOpts{
createOpts := hcloud.FloatingIPCreateOpts{
Type: hcloud.FloatingIPType(typ),
Description: &description,
Labels: labels,
}
if name != "" {
opts.Name = &name
createOpts.Name = &name
}
if homeLocation != "" {
opts.HomeLocation = &hcloud.Location{Name: homeLocation}
createOpts.HomeLocation = &hcloud.Location{Name: homeLocation}
}
if serverNameOrID != "" {
server, _, err := client.Server().Get(ctx, serverNameOrID)
Expand All @@ -76,16 +85,16 @@ var CreateCommand = base.Cmd{
if server == nil {
return fmt.Errorf("server not found: %s", serverNameOrID)
}
opts.Server = server
createOpts.Server = server
}

result, _, err := client.FloatingIP().Create(ctx, opts)
result, _, err := client.FloatingIP().Create(ctx, createOpts)
if err != nil {
return err
}

fmt.Printf("Floating IP %d created\n", result.FloatingIP.ID)

return nil
return changeProtection(ctx, client, waiter, result.FloatingIP, true, protectionOps)
},
}
26 changes: 20 additions & 6 deletions internal/cmd/loadbalancer/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ var CreateCommand = base.Cmd{

cmd.Flags().StringToString("label", nil, "User-defined labels ('key=value') (can be specified multiple times)")

cmd.Flags().StringSlice("enable-protection", []string{}, "Enable protection (delete) (default: none)")
cmd.RegisterFlagCompletionFunc("enable-protection", cmpl.SuggestCandidates("delete"))

return cmd
},
Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
Expand All @@ -51,24 +54,30 @@ var CreateCommand = base.Cmd{
location, _ := cmd.Flags().GetString("location")
networkZone, _ := cmd.Flags().GetString("network-zone")
labels, _ := cmd.Flags().GetStringToString("label")
protection, _ := cmd.Flags().GetStringSlice("enable-protection")

protectionOpts, err := getChangeProtectionOpts(true, protection)
if err != nil {
return err
}

opts := hcloud.LoadBalancerCreateOpts{
createOpts := hcloud.LoadBalancerCreateOpts{
Name: name,
LoadBalancerType: &hcloud.LoadBalancerType{
Name: serverType,
},
Labels: labels,
}
if algorithmType != "" {
opts.Algorithm = &hcloud.LoadBalancerAlgorithm{Type: hcloud.LoadBalancerAlgorithmType(algorithmType)}
createOpts.Algorithm = &hcloud.LoadBalancerAlgorithm{Type: hcloud.LoadBalancerAlgorithmType(algorithmType)}
}
if networkZone != "" {
opts.NetworkZone = hcloud.NetworkZone(networkZone)
createOpts.NetworkZone = hcloud.NetworkZone(networkZone)
}
if location != "" {
opts.Location = &hcloud.Location{Name: location}
createOpts.Location = &hcloud.Location{Name: location}
}
result, _, err := client.LoadBalancer().Create(ctx, opts)
result, _, err := client.LoadBalancer().Create(ctx, createOpts)
if err != nil {
return err
}
Expand All @@ -80,7 +89,12 @@ var CreateCommand = base.Cmd{
if err != nil {
return err
}
fmt.Printf("LoadBalancer %d created\n", loadBalancer.ID)
fmt.Printf("Load Balancer %d created\n", loadBalancer.ID)

if err := changeProtection(ctx, client, waiter, loadBalancer, true, protectionOpts); err != nil {
return err
}

fmt.Printf("IPv4: %s\n", loadBalancer.PublicNet.IPv4.IP.String())
fmt.Printf("IPv6: %s\n", loadBalancer.PublicNet.IPv6.IP.String())
return nil
Expand Down
20 changes: 15 additions & 5 deletions internal/cmd/network/create.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package network

import (
"fmt"
"github.com/hetznercloud/cli/internal/cmd/cmpl"
"github.com/hetznercloud/cli/internal/hcapi2"
"net"

"github.com/hetznercloud/cli/internal/state"
Expand Down Expand Up @@ -30,6 +31,8 @@ func newCreateCommand(cli *state.State) *cobra.Command {

cmd.Flags().StringToString("label", nil, "User-defined labels ('key=value') (can be specified multiple times)")

cmd.Flags().StringSlice("enable-protection", []string{}, "Enable protection (delete) (default: none)")
cmd.RegisterFlagCompletionFunc("enable-protection", cmpl.SuggestCandidates("delete"))
return cmd
}

Expand All @@ -38,19 +41,26 @@ func runCreate(cli *state.State, cmd *cobra.Command, args []string) error {
ipRange, _ := cmd.Flags().GetIPNet("ip-range")
labels, _ := cmd.Flags().GetStringToString("label")
exposeRoutesToVSwitch, _ := cmd.Flags().GetBool("expose-routes-to-vswitch")
protection, _ := cmd.Flags().GetStringSlice("enable-protection")

opts := hcloud.NetworkCreateOpts{
protectionOpts, err := getChangeProtectionOpts(true, protection)
if err != nil {
return err
}

createOpts := hcloud.NetworkCreateOpts{
Name: name,
IPRange: &ipRange,
Labels: labels,
ExposeRoutesToVSwitch: exposeRoutesToVSwitch,
}

network, _, err := cli.Client().Network.Create(cli.Context, opts)
network, _, err := cli.Client().Network.Create(cli.Context, createOpts)
if err != nil {
return err
}

fmt.Printf("Network %d created\n", network.ID)
return nil
cmd.Printf("Network %d created\n", network.ID)

return changeProtection(cli.Context, hcapi2.NewClient(cli.Client()), cli, network, true, protectionOpts)
}
23 changes: 19 additions & 4 deletions internal/cmd/primaryip/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package primaryip
import (
"context"
"fmt"

"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/cmd/cmpl"
"github.com/hetznercloud/cli/internal/hcapi2"
Expand Down Expand Up @@ -34,31 +33,47 @@ var CreateCmd = base.Cmd{
cmd.RegisterFlagCompletionFunc("datacenter", cmpl.SuggestCandidatesF(client.Datacenter().Names))

cmd.Flags().StringToString("label", nil, "User-defined labels ('key=value') (can be specified multiple times)")

cmd.Flags().StringSlice("enable-protection", []string{}, "Enable protection (delete) (default: none)")
cmd.RegisterFlagCompletionFunc("enable-protection", cmpl.SuggestCandidates("delete"))

return cmd
},
Run: func(ctx context.Context, client hcapi2.Client, actionWaiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
typ, _ := cmd.Flags().GetString("type")
name, _ := cmd.Flags().GetString("name")
assigneeID, _ := cmd.Flags().GetInt64("assignee-id")
datacenter, _ := cmd.Flags().GetString("datacenter")
protection, _ := cmd.Flags().GetStringSlice("enable-protection")

opts := hcloud.PrimaryIPCreateOpts{
protectionOpts, err := getChangeProtectionOpts(true, protection)
if err != nil {
return err
}

createOpts := hcloud.PrimaryIPCreateOpts{
Type: hcloud.PrimaryIPType(typ),
Name: name,
AssigneeType: "server",
Datacenter: datacenter,
}
if assigneeID != 0 {
opts.AssigneeID = &assigneeID
createOpts.AssigneeID = &assigneeID
}

result, _, err := client.PrimaryIP().Create(ctx, opts)
result, _, err := client.PrimaryIP().Create(ctx, createOpts)
if err != nil {
return err
}

fmt.Printf("Primary IP %d created\n", result.PrimaryIP.ID)

if len(protection) > 0 {
if err := changeProtection(ctx, client, actionWaiter, result.PrimaryIP, true, protectionOpts); err != nil {
return err
}
}

return nil
},
}
39 changes: 25 additions & 14 deletions internal/cmd/server/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,20 @@ var CreateCmd = base.Cmd{

cmd.Flags().Bool("without-ipv4", false, "Creates the server without an IPv4 (default: false)")
cmd.Flags().Bool("without-ipv6", false, "Creates the server without an IPv6 (default: false)")

cmd.Flags().StringSlice("enable-protection", []string{}, "Enable protection (delete, rebuild) (default: none)")
cmd.RegisterFlagCompletionFunc("enable-protection", cmpl.SuggestCandidates("delete", "rebuild"))

return cmd
},

Run: func(ctx context.Context, client hcapi2.Client, actionWaiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
opts, err := createOptsFromFlags(ctx, client, cmd.Flags())
createOpts, protectionOpts, err := createOptsFromFlags(ctx, client, cmd.Flags())
if err != nil {
return err
}

result, _, err := client.Server().Create(ctx, opts)
result, _, err := client.Server().Create(ctx, createOpts)
if err != nil {
return err
}
Expand All @@ -103,6 +107,11 @@ var CreateCmd = base.Cmd{
return err
}
fmt.Printf("Server %d created\n", result.Server.ID)

if err := changeProtection(ctx, client, actionWaiter, server, true, protectionOpts); err != nil {
return err
}

if !server.PublicNet.IPv4.IsUnspecified() {
fmt.Printf("IPv4: %s\n", server.PublicNet.IPv4.IP.String())
}
Expand Down Expand Up @@ -196,7 +205,7 @@ func buildUserData(files []string) (string, error) {

func createOptsFromFlags(
ctx context.Context, client hcapi2.Client, flags *pflag.FlagSet,
) (opts hcloud.ServerCreateOpts, err error) {
) (createOpts hcloud.ServerCreateOpts, protectionOps hcloud.ServerChangeProtectionOpts, err error) {
name, _ := flags.GetString("name")
serverTypeName, _ := flags.GetString("type")
imageIDorName, _ := flags.GetString("image")
Expand All @@ -216,6 +225,7 @@ func createOptsFromFlags(
withoutIPv6, _ := flags.GetBool("without-ipv6")
primaryIPv4IDorName, _ := flags.GetString("primary-ipv4")
primaryIPv6IDorName, _ := flags.GetString("primary-ipv6")
protection, _ := flags.GetStringSlice("enable-protection")

serverType, _, err := client.ServerType().Get(ctx, serverTypeName)
if err != nil {
Expand Down Expand Up @@ -254,7 +264,7 @@ func createOptsFromFlags(
err = fmt.Errorf("a server can not be created without IPv4, IPv6 and a private network. Choose at least one of those options to create the server")
return
}
opts = hcloud.ServerCreateOpts{
createOpts = hcloud.ServerCreateOpts{
Name: name,
ServerType: serverType,
Image: image,
Expand Down Expand Up @@ -293,7 +303,7 @@ func createOptsFromFlags(
}
publicNetConfiguration.IPv6 = primaryIPv6
}
opts.PublicNet = publicNetConfiguration
createOpts.PublicNet = publicNetConfiguration
if len(userDataFiles) == 1 {
var data []byte
if userDataFiles[0] == "-" {
Expand All @@ -304,9 +314,9 @@ func createOptsFromFlags(
if err != nil {
return
}
opts.UserData = string(data)
createOpts.UserData = string(data)
} else if len(userDataFiles) > 1 {
opts.UserData, err = buildUserData(userDataFiles)
createOpts.UserData, err = buildUserData(userDataFiles)
if err != nil {
return
}
Expand All @@ -330,7 +340,7 @@ func createOptsFromFlags(
err = fmt.Errorf("SSH key not found: %s", sshKeyIDOrName)
return
}
opts.SSHKeys = append(opts.SSHKeys, sshKey)
createOpts.SSHKeys = append(createOpts.SSHKeys, sshKey)
}
for _, volumeIDOrName := range volumes {
var volume *hcloud.Volume
Expand All @@ -343,7 +353,7 @@ func createOptsFromFlags(
err = fmt.Errorf("volume not found: %s", volumeIDOrName)
return
}
opts.Volumes = append(opts.Volumes, volume)
createOpts.Volumes = append(createOpts.Volumes, volume)
}
for _, networkIDOrName := range networks {
var network *hcloud.Network
Expand All @@ -356,7 +366,7 @@ func createOptsFromFlags(
err = fmt.Errorf("network not found: %s", networkIDOrName)
return
}
opts.Networks = append(opts.Networks, network)
createOpts.Networks = append(createOpts.Networks, network)
}
for _, firewallIDOrName := range firewalls {
var firewall *hcloud.Firewall
Expand All @@ -369,14 +379,14 @@ func createOptsFromFlags(
err = fmt.Errorf("firewall not found: %s", firewallIDOrName)
return
}
opts.Firewalls = append(opts.Firewalls, &hcloud.ServerCreateFirewall{Firewall: *firewall})
createOpts.Firewalls = append(createOpts.Firewalls, &hcloud.ServerCreateFirewall{Firewall: *firewall})
}

if datacenter != "" {
opts.Datacenter = &hcloud.Datacenter{Name: datacenter}
createOpts.Datacenter = &hcloud.Datacenter{Name: datacenter}
}
if location != "" {
opts.Location = &hcloud.Location{Name: location}
createOpts.Location = &hcloud.Location{Name: location}
}
if placementGroupIDorName != "" {
var placementGroup *hcloud.PlacementGroup
Expand All @@ -388,9 +398,10 @@ func createOptsFromFlags(
err = fmt.Errorf("placement group not found: %s", placementGroupIDorName)
return
}
opts.PlacementGroup = placementGroup
createOpts.PlacementGroup = placementGroup
}

protectionOps, err = getChangeProtectionOpts(true, protection)
return
}

Expand Down

0 comments on commit e313e69

Please sign in to comment.