loadbalancer

package
v1.37.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2023 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AddServiceCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "add-service LOADBALANCER FLAGS",
			Short:                 "Add a service from a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
		cmd.Flags().String("protocol", "", "Protocol of the service (required)")
		cmd.MarkFlagRequired("protocol")

		cmd.Flags().Int("listen-port", 0, "Listen port of the service")
		cmd.Flags().Int("destination-port", 0, "Destination port of the service on the targets")
		cmd.Flags().Bool("proxy-protocol", false, "Enable proxyprotocol")

		cmd.Flags().Bool("http-sticky-sessions", false, "Enable Sticky Sessions")
		cmd.Flags().String("http-cookie-name", "", "Sticky Sessions: Cookie Name we set")
		cmd.Flags().Duration("http-cookie-lifetime", 0, "Sticky Sessions: Lifetime of the cookie")
		cmd.Flags().Int64Slice("http-certificates", []int64{}, "ID of Certificates which are attached to this Load Balancer")
		cmd.Flags().Bool("http-redirect-http", false, "Redirect all traffic on port 80 to port 443")

		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		protocol, _ := cmd.Flags().GetString("protocol")
		listenPort, _ := cmd.Flags().GetInt("listen-port")
		destinationPort, _ := cmd.Flags().GetInt("destination-port")
		httpCertificates, _ := cmd.Flags().GetInt64Slice("http-certificates")

		if protocol == "" {
			return fmt.Errorf("required flag protocol not set")
		}

		switch hcloud.LoadBalancerServiceProtocol(protocol) {
		case hcloud.LoadBalancerServiceProtocolHTTP:
			break
		case hcloud.LoadBalancerServiceProtocolTCP:
			if listenPort == 0 {
				return fmt.Errorf("please specify a listen port")
			}

			if destinationPort == 0 {
				return fmt.Errorf("please specify a destination port")
			}
			break
		case hcloud.LoadBalancerServiceProtocolHTTPS:
			if len(httpCertificates) == 0 {
				return fmt.Errorf("no certificate specified")
			}
		default:
			return fmt.Errorf("%s is not a valid protocol", protocol)
		}
		if listenPort > 65535 {
			return fmt.Errorf("%d is not a valid listen port", listenPort)
		}

		if destinationPort > 65535 {
			return fmt.Errorf("%d is not a valid destination port", destinationPort)
		}

		idOrName := args[0]

		proxyProtocol, _ := cmd.Flags().GetBool("proxy-protocol")
		httpStickySessions, _ := cmd.Flags().GetBool("http-sticky-sessions")
		httpCookieName, _ := cmd.Flags().GetString("http-cookie-name")
		httpCookieLifetime, _ := cmd.Flags().GetDuration("http-cookie-lifetime")
		httpRedirect, _ := cmd.Flags().GetBool("http-redirect-http")

		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		opts := hcloud.LoadBalancerAddServiceOpts{
			Protocol:      hcloud.LoadBalancerServiceProtocol(protocol),
			Proxyprotocol: hcloud.Bool(proxyProtocol),
		}

		if listenPort != 0 {
			opts.ListenPort = hcloud.Int(listenPort)
		}
		if destinationPort != 0 {
			opts.DestinationPort = hcloud.Int(destinationPort)
		}

		if protocol != string(hcloud.LoadBalancerServiceProtocolTCP) {
			opts.HTTP = &hcloud.LoadBalancerAddServiceOptsHTTP{
				StickySessions: hcloud.Bool(httpStickySessions),
				RedirectHTTP:   hcloud.Bool(httpRedirect),
			}
			if httpCookieName != "" {
				opts.HTTP.CookieName = hcloud.String(httpCookieName)
			}
			if httpCookieLifetime != 0 {
				opts.HTTP.CookieLifetime = hcloud.Duration(httpCookieLifetime)
			}
			for _, certificateID := range httpCertificates {
				opts.HTTP.Certificates = append(opts.HTTP.Certificates, &hcloud.Certificate{ID: certificateID})
			}
		}
		action, _, err := client.LoadBalancer().AddService(ctx, loadBalancer, opts)
		if err != nil {
			return err
		}
		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}
		fmt.Printf("Service was added to Load Balancer %d\n", loadBalancer.ID)

		return nil
	},
}
View Source
var AddTargetCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "add-target LOADBALANCER FLAGS",
			Short:                 "Add a target to a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("server", "", "Name or ID of the server")
		cmd.RegisterFlagCompletionFunc("server", cmpl.SuggestCandidatesF(client.Server().Names))

		cmd.Flags().String("label-selector", "", "Label Selector")

		cmd.Flags().Bool("use-private-ip", false, "Determine if the Load Balancer should connect to the target via the network")
		cmd.Flags().String("ip", "", "Use the passed IP address as target")
		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		var (
			action       *hcloud.Action
			loadBalancer *hcloud.LoadBalancer
			err          error
		)

		idOrName := args[0]
		usePrivateIP, _ := cmd.Flags().GetBool("use-private-ip")
		serverIDOrName, _ := cmd.Flags().GetString("server")
		labelSelector, _ := cmd.Flags().GetString("label-selector")
		ipAddr, _ := cmd.Flags().GetString("ip")

		if !util.ExactlyOneSet(serverIDOrName, labelSelector, ipAddr) {
			return fmt.Errorf("--server, --label-selector, and --ip are mutually exclusive")
		}
		if loadBalancer, _, err = client.LoadBalancer().Get(ctx, idOrName); err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		switch {
		case serverIDOrName != "":
			server, _, err := client.Server().Get(ctx, serverIDOrName)
			if err != nil {
				return err
			}
			if server == nil {
				return fmt.Errorf("server not found: %s", serverIDOrName)
			}
			action, _, err = client.LoadBalancer().AddServerTarget(ctx, loadBalancer, hcloud.LoadBalancerAddServerTargetOpts{
				Server:       server,
				UsePrivateIP: hcloud.Bool(usePrivateIP),
			})
			if err != nil {
				return err
			}
		case labelSelector != "":
			action, _, err = client.LoadBalancer().AddLabelSelectorTarget(ctx, loadBalancer, hcloud.LoadBalancerAddLabelSelectorTargetOpts{
				Selector:     labelSelector,
				UsePrivateIP: hcloud.Bool(usePrivateIP),
			})
			if err != nil {
				return err
			}
		case ipAddr != "":
			ip := net.ParseIP(ipAddr)
			if ip == nil {
				return fmt.Errorf("invalid ip provided")
			}
			action, _, err = client.LoadBalancer().AddIPTarget(ctx, loadBalancer, hcloud.LoadBalancerAddIPTargetOpts{
				IP: ip,
			})
			if err != nil {
				return err
			}
		default:
			return fmt.Errorf("specify one of --server, --label-selector, or --ip")
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}
		fmt.Printf("Target added to Load Balancer %d\n", loadBalancer.ID)

		return nil
	},
}
View Source
var AttachToNetworkCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "attach-to-network [FLAGS] LOADBALANCER",
			Short:                 "Attach a Load Balancer to a Network",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().StringP("network", "n", "", "Network (ID or name) (required)")
		cmd.RegisterFlagCompletionFunc("network", cmpl.SuggestCandidatesF(client.Network().Names))
		cmd.MarkFlagRequired("network")

		cmd.Flags().IP("ip", nil, "IP address to assign to the Load Balancer (auto-assigned if omitted)")

		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		networkIDOrName, _ := cmd.Flags().GetString("network")
		network, _, err := client.Network().Get(ctx, networkIDOrName)
		if err != nil {
			return err
		}
		if network == nil {
			return fmt.Errorf("network not found: %s", networkIDOrName)
		}

		ip, _ := cmd.Flags().GetIP("ip")

		opts := hcloud.LoadBalancerAttachToNetworkOpts{
			Network: network,
			IP:      ip,
		}
		action, _, err := client.LoadBalancer().AttachToNetwork(ctx, loadBalancer, opts)

		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("Load Balancer %d attached to network %d\n", loadBalancer.ID, network.ID)
		return nil
	},
}
View Source
var ChangeAlgorithmCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "change-algorithm LOADBALANCER FLAGS",
			Short:                 "Changes the algorithm of a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("algorithm-type", "", "The new algorithm of the Load Balancer")
		cmd.RegisterFlagCompletionFunc("algorithm-type", cmpl.SuggestCandidates(
			string(hcloud.LoadBalancerAlgorithmTypeRoundRobin),
			string(hcloud.LoadBalancerAlgorithmTypeLeastConnections),
		))
		cmd.MarkFlagRequired("algorithm-type")

		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		algorithm, _ := cmd.Flags().GetString("algorithm-type")
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		action, _, err := client.LoadBalancer().ChangeAlgorithm(ctx, loadBalancer, hcloud.LoadBalancerChangeAlgorithmOpts{Type: hcloud.LoadBalancerAlgorithmType(algorithm)})
		if err != nil {
			return err
		}
		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}
		fmt.Printf("Algorithm for Load Balancer %d was changed\n", loadBalancer.ID)

		return nil
	},
}
View Source
var ChangeTypeCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:   "change-type [FLAGS] LOADBALANCER LOADBALANCERTYPE",
			Short: "Change type of a Load Balancer",
			Args:  cobra.ExactArgs(2),
			ValidArgsFunction: cmpl.SuggestArgs(
				cmpl.SuggestCandidatesF(client.LoadBalancer().Names),
				cmpl.SuggestCandidatesF(client.LoadBalancerType().Names),
			),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		loadBalancerTypeIDOrName := args[1]
		loadBalancerType, _, err := client.LoadBalancerType().Get(ctx, loadBalancerTypeIDOrName)
		if err != nil {
			return err
		}
		if loadBalancerType == nil {
			return fmt.Errorf("Load Balancer type not found: %s", loadBalancerTypeIDOrName)
		}

		opts := hcloud.LoadBalancerChangeTypeOpts{
			LoadBalancerType: loadBalancerType,
		}
		action, _, err := client.LoadBalancer().ChangeType(ctx, loadBalancer, opts)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("LoadBalancer %d changed to type %s\n", loadBalancer.ID, loadBalancerType.Name)
		return nil
	},
}
View Source
var CreateCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "create [FLAGS]",
			Short:                 "Create a Load Balancer",
			Args:                  cobra.NoArgs,
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("name", "", "Load Balancer name (required)")
		cmd.MarkFlagRequired("name")

		cmd.Flags().String("type", "", "Load Balancer type (ID or name) (required)")
		cmd.RegisterFlagCompletionFunc("type", cmpl.SuggestCandidatesF(client.LoadBalancerType().Names))
		cmd.MarkFlagRequired("type")

		cmd.Flags().String("algorithm-type", "", "Algorithm Type name (round_robin or least_connections)")
		cmd.RegisterFlagCompletionFunc("algorithm-type", cmpl.SuggestCandidates(
			string(hcloud.LoadBalancerAlgorithmTypeLeastConnections),
			string(hcloud.LoadBalancerAlgorithmTypeRoundRobin),
		))
		cmd.Flags().String("location", "", "Location (ID or name)")
		cmd.RegisterFlagCompletionFunc("location", cmpl.SuggestCandidatesF(client.Location().Names))

		cmd.Flags().String("network-zone", "", "Network Zone")
		cmd.RegisterFlagCompletionFunc("network-zone", cmpl.SuggestCandidatesF(client.Location().NetworkZones))

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

		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		name, _ := cmd.Flags().GetString("name")
		serverType, _ := cmd.Flags().GetString("type")
		algorithmType, _ := cmd.Flags().GetString("algorithm-type")
		location, _ := cmd.Flags().GetString("location")
		networkZone, _ := cmd.Flags().GetString("network-zone")
		labels, _ := cmd.Flags().GetStringToString("label")

		opts := hcloud.LoadBalancerCreateOpts{
			Name: name,
			LoadBalancerType: &hcloud.LoadBalancerType{
				Name: serverType,
			},
			Labels: labels,
		}
		if algorithmType != "" {
			opts.Algorithm = &hcloud.LoadBalancerAlgorithm{Type: hcloud.LoadBalancerAlgorithmType(algorithmType)}
		}
		if networkZone != "" {
			opts.NetworkZone = hcloud.NetworkZone(networkZone)
		}
		if location != "" {
			opts.Location = &hcloud.Location{Name: location}
		}
		result, _, err := client.LoadBalancer().Create(ctx, opts)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, result.Action); err != nil {
			return err
		}
		loadBalancer, _, err := client.LoadBalancer().GetByID(ctx, result.LoadBalancer.ID)
		if err != nil {
			return err
		}
		fmt.Printf("LoadBalancer %d created\n", loadBalancer.ID)
		fmt.Printf("IPv4: %s\n", loadBalancer.PublicNet.IPv4.IP.String())
		fmt.Printf("IPv6: %s\n", loadBalancer.PublicNet.IPv6.IP.String())
		return nil
	},
}
View Source
var DeleteServiceCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "delete-service [FLAGS] LOADBALANCER",
			Short:                 "Deletes a service from a Load Balancer",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			Args:                  cobra.RangeArgs(1, 2),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().Int("listen-port", 0, "The listen port of the service you want to delete (required)")
		cmd.MarkFlagRequired("listen-port")
		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		listenPort, _ := cmd.Flags().GetInt("listen-port")
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}
		_, _, err = client.LoadBalancer().DeleteService(ctx, loadBalancer, listenPort)
		if err != nil {
			return err
		}

		fmt.Printf("Service on port %d deleted from Load Balancer %d\n", listenPort, loadBalancer.ID)
		return nil
	},
}
View Source
var DescribeCmd = base.DescribeCmd{
	ResourceNameSingular: "Load Balancer",
	ShortDescription:     "Describe a Load Balancer",
	JSONKeyGetByID:       "load_balancer",
	JSONKeyGetByName:     "load_balancers",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
	Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
		return client.LoadBalancer().Get(ctx, idOrName)
	},
	AdditionalFlags: func(cmd *cobra.Command) {
		cmd.Flags().Bool("expand-targets", false, "Expand all label_selector targets")
	},
	PrintText: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
		withLabelSelectorTargets, _ := cmd.Flags().GetBool("expand-targets")
		loadBalancer := resource.(*hcloud.LoadBalancer)
		fmt.Printf("ID:\t\t\t\t%d\n", loadBalancer.ID)
		fmt.Printf("Name:\t\t\t\t%s\n", loadBalancer.Name)
		fmt.Printf("Created:\t\t\t%s (%s)\n", util.Datetime(loadBalancer.Created), humanize.Time(loadBalancer.Created))
		fmt.Printf("Public Net:\n")
		fmt.Printf("  Enabled:\t\t\t%s\n", util.YesNo(loadBalancer.PublicNet.Enabled))
		fmt.Printf("  IPv4:\t\t\t\t%s\n", loadBalancer.PublicNet.IPv4.IP.String())
		fmt.Printf("  IPv4 DNS PTR:\t\t\t%s\n", loadBalancer.PublicNet.IPv4.DNSPtr)
		fmt.Printf("  IPv6:\t\t\t\t%s\n", loadBalancer.PublicNet.IPv6.IP.String())
		fmt.Printf("  IPv6 DNS PTR:\t\t\t%s\n", loadBalancer.PublicNet.IPv6.DNSPtr)

		fmt.Printf("Private Net:\n")
		if len(loadBalancer.PrivateNet) > 0 {
			for _, n := range loadBalancer.PrivateNet {
				fmt.Printf("  - ID:\t\t\t%d\n", n.Network.ID)
				fmt.Printf("    Name:\t\t%s\n", client.Network().Name(n.Network.ID))
				fmt.Printf("    IP:\t\t\t%s\n", n.IP.String())
			}
		} else {
			fmt.Printf("    No Private Network\n")
		}
		fmt.Printf("Algorithm:\t\t\t%s\n", loadBalancer.Algorithm.Type)

		fmt.Printf("Load Balancer Type:\t\t%s (ID: %d)\n", loadBalancer.LoadBalancerType.Name, loadBalancer.LoadBalancerType.ID)
		fmt.Printf("  ID:\t\t\t\t%d\n", loadBalancer.LoadBalancerType.ID)
		fmt.Printf("  Name:\t\t\t\t%s\n", loadBalancer.LoadBalancerType.Name)
		fmt.Printf("  Description:\t\t\t%s\n", loadBalancer.LoadBalancerType.Description)
		fmt.Printf("  Max Services:\t\t\t%d\n", loadBalancer.LoadBalancerType.MaxServices)
		fmt.Printf("  Max Connections:\t\t%d\n", loadBalancer.LoadBalancerType.MaxConnections)
		fmt.Printf("  Max Targets:\t\t\t%d\n", loadBalancer.LoadBalancerType.MaxTargets)
		fmt.Printf("  Max assigned Certificates:\t%d\n", loadBalancer.LoadBalancerType.MaxAssignedCertificates)

		fmt.Printf("Services:\n")
		if len(loadBalancer.Services) == 0 {
			fmt.Print("  No services\n")
		} else {
			for _, service := range loadBalancer.Services {
				fmt.Printf("  - Protocol:\t\t\t%s\n", service.Protocol)
				fmt.Printf("    Listen Port:\t\t%d\n", service.ListenPort)
				fmt.Printf("    Destination Port:\t\t%d\n", service.DestinationPort)
				fmt.Printf("    Proxy Protocol:\t\t%s\n", util.YesNo(service.Proxyprotocol))
				if service.Protocol != hcloud.LoadBalancerServiceProtocolTCP {
					fmt.Printf("    Sticky Sessions:\t\t%s\n", util.YesNo(service.HTTP.StickySessions))
					if service.HTTP.StickySessions {
						fmt.Printf("    Sticky Cookie Name:\t\t%s\n", service.HTTP.CookieName)
						fmt.Printf("    Sticky Cookie Lifetime:\t%vs\n", service.HTTP.CookieLifetime.Seconds())
					}
					if service.Protocol == hcloud.LoadBalancerServiceProtocolHTTPS {
						fmt.Printf("    Certificates:\n")
						for _, cert := range service.HTTP.Certificates {
							fmt.Printf("      - ID: \t\t\t%v\n", cert.ID)
						}
					}
				}

				fmt.Printf("    Health Check:\n")
				fmt.Printf("      Protocol:\t\t\t%s\n", service.HealthCheck.Protocol)
				fmt.Printf("      Timeout:\t\t\t%vs\n", service.HealthCheck.Timeout.Seconds())
				fmt.Printf("      Interval:\t\t\tevery %vs\n", service.HealthCheck.Interval.Seconds())
				fmt.Printf("      Retries:\t\t\t%d\n", service.HealthCheck.Retries)
				if service.HealthCheck.Protocol != hcloud.LoadBalancerServiceProtocolTCP {
					fmt.Printf("      HTTP Domain:\t\t%s\n", service.HealthCheck.HTTP.Domain)
					fmt.Printf("      HTTP Path:\t\t%s\n", service.HealthCheck.HTTP.Path)
					fmt.Printf("      Response:\t\t%s\n", service.HealthCheck.HTTP.Response)
					fmt.Printf("      TLS:\t\t\t%s\n", util.YesNo(service.HealthCheck.HTTP.TLS))
					fmt.Printf("      Status Codes:\t\t%v\n", service.HealthCheck.HTTP.StatusCodes)
				}
			}
		}

		fmt.Printf("Targets:\n")
		if len(loadBalancer.Targets) == 0 {
			fmt.Print("  No targets\n")
		}
		for _, target := range loadBalancer.Targets {
			fmt.Printf("  - Type:\t\t\t%s\n", target.Type)
			switch target.Type {
			case hcloud.LoadBalancerTargetTypeServer:
				fmt.Printf("    Server:\n")
				fmt.Printf("      ID:\t\t\t%d\n", target.Server.Server.ID)
				fmt.Printf("      Name:\t\t\t%s\n", client.Server().ServerName(target.Server.Server.ID))
				fmt.Printf("    Use Private IP:\t\t%s\n", util.YesNo(target.UsePrivateIP))
				fmt.Printf("    Status:\n")
				for _, healthStatus := range target.HealthStatus {
					fmt.Printf("    - Service:\t\t\t%d\n", healthStatus.ListenPort)
					fmt.Printf("      Status:\t\t\t%s\n", healthStatus.Status)
				}
			case hcloud.LoadBalancerTargetTypeLabelSelector:
				fmt.Printf("    Label Selector:\t\t%s\n", target.LabelSelector.Selector)
				fmt.Printf("      Targets: (%d)\n", len(target.Targets))
				if len(target.Targets) == 0 {
					fmt.Print("      No targets\n")
				}
				if !withLabelSelectorTargets {
					continue
				}
				for _, lbtarget := range target.Targets {
					fmt.Printf("      - Type:\t\t\t\t%s\n", lbtarget.Type)
					fmt.Printf("        Server ID:\t\t\t%d\n", lbtarget.Server.Server.ID)
					fmt.Printf("        Status:\n")
					for _, healthStatus := range lbtarget.HealthStatus {
						fmt.Printf("          - Service:\t\t\t%d\n", healthStatus.ListenPort)
						fmt.Printf("            Status:\t\t\t%s\n", healthStatus.Status)
					}
				}
			case hcloud.LoadBalancerTargetTypeIP:
				fmt.Printf("    IP:\t\t\t\t%s\n", target.IP.IP)
				fmt.Printf("    Status:\n")
				for _, healthStatus := range target.HealthStatus {
					fmt.Printf("    - Service:\t\t\t%d\n", healthStatus.ListenPort)
					fmt.Printf("      Status:\t\t\t%s\n", healthStatus.Status)
				}
			}
		}

		fmt.Printf("Traffic:\n")
		fmt.Printf("  Outgoing:\t%v\n", humanize.IBytes(loadBalancer.OutgoingTraffic))
		fmt.Printf("  Ingoing:\t%v\n", humanize.IBytes(loadBalancer.IngoingTraffic))
		fmt.Printf("  Included:\t%v\n", humanize.IBytes(loadBalancer.IncludedTraffic))

		fmt.Printf("Protection:\n")
		fmt.Printf("  Delete:\t%s\n", util.YesNo(loadBalancer.Protection.Delete))

		fmt.Print("Labels:\n")
		if len(loadBalancer.Labels) == 0 {
			fmt.Print("  No labels\n")
		} else {
			for key, value := range loadBalancer.Labels {
				fmt.Printf("  %s: %s\n", key, value)
			}
		}

		return nil
	},
}

DescribeCmd defines a command for describing a LoadBalancer.

View Source
var DetachFromNetworkCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "detach-from-network [FLAGS] LOADBALANCER",
			Short:                 "Detach a Load Balancer from a Network",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
		cmd.Flags().StringP("network", "n", "", "Network (ID or name) (required)")
		cmd.RegisterFlagCompletionFunc("network", cmpl.SuggestCandidatesF(client.Network().Names))
		cmd.MarkFlagRequired("network")
		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}
		networkIDOrName, _ := cmd.Flags().GetString("network")
		network, _, err := client.Network().Get(ctx, networkIDOrName)
		if err != nil {
			return err
		}
		if network == nil {
			return fmt.Errorf("network not found: %s", networkIDOrName)
		}

		opts := hcloud.LoadBalancerDetachFromNetworkOpts{
			Network: network,
		}
		action, _, err := client.LoadBalancer().DetachFromNetwork(ctx, loadBalancer, opts)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("Load Balancer %d detached from Network %d\n", loadBalancer.ID, network.ID)
		return nil
	},
}
View Source
var DisableProtectionCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:   "disable-protection [FLAGS] LOADBALANCER PROTECTIONLEVEL [PROTECTIONLEVEL...]",
			Short: "Disable resource protection for a Load Balancer",
			Args:  cobra.MinimumNArgs(2),
			ValidArgsFunction: cmpl.SuggestArgs(
				cmpl.SuggestCandidatesF(client.LoadBalancer().Names),
				cmpl.SuggestCandidates("delete"),
			),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		var unknown []string
		opts := hcloud.LoadBalancerChangeProtectionOpts{}
		for _, arg := range args[1:] {
			switch strings.ToLower(arg) {
			case "delete":
				opts.Delete = hcloud.Bool(false)
			default:
				unknown = append(unknown, arg)
			}
		}
		if len(unknown) > 0 {
			return fmt.Errorf("unknown protection level: %s", strings.Join(unknown, ", "))
		}

		action, _, err := client.LoadBalancer().ChangeProtection(ctx, loadBalancer, opts)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("Resource protection disabled for Load Balancer %d\n", loadBalancer.ID)
		return nil
	},
}
View Source
var DisablePublicInterfaceCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:                   "disable-public-interface [FLAGS] LOADBALANCER",
			Short:                 "Disable the public interface of a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		action, _, err := client.LoadBalancer().DisablePublicInterface(ctx, loadBalancer)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("Public interface of Load Balancer %d was disabled\n", loadBalancer.ID)
		return nil
	},
}
View Source
var EnableProtectionCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:   "enable-protection [FLAGS] LOADBALANCER PROTECTIONLEVEL [PROTECTIONLEVEL...]",
			Short: "Enable resource protection for a Load Balancer",
			Args:  cobra.MinimumNArgs(2),
			ValidArgsFunction: cmpl.SuggestArgs(
				cmpl.SuggestCandidatesF(client.LoadBalancer().Names),
				cmpl.SuggestCandidates("delete"),
			),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		LoadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if LoadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		var unknown []string
		opts := hcloud.LoadBalancerChangeProtectionOpts{}
		for _, arg := range args[1:] {
			switch strings.ToLower(arg) {
			case "delete":
				opts.Delete = hcloud.Bool(true)
			default:
				unknown = append(unknown, arg)
			}
		}
		if len(unknown) > 0 {
			return fmt.Errorf("unknown protection level: %s", strings.Join(unknown, ", "))
		}

		action, _, err := client.LoadBalancer().ChangeProtection(ctx, LoadBalancer, opts)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("Resource protection enabled Load Balancer %d\n", LoadBalancer.ID)
		return nil
	},
}
View Source
var EnablePublicInterfaceCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:                   "enable-public-interface [FLAGS] LOADBALANCER",
			Short:                 "Enable the public interface of a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		action, _, err := client.LoadBalancer().EnablePublicInterface(ctx, loadBalancer)
		if err != nil {
			return err
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}

		fmt.Printf("Public interface of Load Balancer %d was enabled\n", loadBalancer.ID)
		return nil
	},
}
View Source
var ListCmd = base.ListCmd{
	ResourceNamePlural: "Load Balancer",

	DefaultColumns: []string{"id", "name", "ipv4", "ipv6", "type", "location", "network_zone", "age"},
	Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) {
		opts := hcloud.LoadBalancerListOpts{ListOpts: listOpts}
		if len(sorts) > 0 {
			opts.Sort = sorts
		}
		loadBalancers, err := client.LoadBalancer().AllWithOpts(ctx, opts)

		var resources []interface{}
		for _, r := range loadBalancers {
			resources = append(resources, r)
		}
		return resources, err
	},

	OutputTable: func(client hcapi2.Client) *output.Table {
		return output.NewTable().
			AddAllowedFields(hcloud.LoadBalancer{}).
			AddFieldFn("ipv4", output.FieldFn(func(obj interface{}) string {
				loadbalancer := obj.(*hcloud.LoadBalancer)
				return loadbalancer.PublicNet.IPv4.IP.String()
			})).
			AddFieldFn("ipv6", output.FieldFn(func(obj interface{}) string {
				loadbalancer := obj.(*hcloud.LoadBalancer)
				return loadbalancer.PublicNet.IPv6.IP.String()
			})).
			AddFieldFn("type", output.FieldFn(func(obj interface{}) string {
				loadbalancer := obj.(*hcloud.LoadBalancer)
				return loadbalancer.LoadBalancerType.Name
			})).
			AddFieldFn("location", output.FieldFn(func(obj interface{}) string {
				loadbalancer := obj.(*hcloud.LoadBalancer)
				return loadbalancer.Location.Name
			})).
			AddFieldFn("network_zone", output.FieldFn(func(obj interface{}) string {
				loadbalancer := obj.(*hcloud.LoadBalancer)
				return string(loadbalancer.Location.NetworkZone)
			})).
			AddFieldFn("labels", output.FieldFn(func(obj interface{}) string {
				loadBalancer := obj.(*hcloud.LoadBalancer)
				return util.LabelsToString(loadBalancer.Labels)
			})).
			AddFieldFn("protection", output.FieldFn(func(obj interface{}) string {
				loadBalancer := obj.(*hcloud.LoadBalancer)
				var protection []string
				if loadBalancer.Protection.Delete {
					protection = append(protection, "delete")
				}
				return strings.Join(protection, ", ")
			})).
			AddFieldFn("created", output.FieldFn(func(obj interface{}) string {
				loadBalancer := obj.(*hcloud.LoadBalancer)
				return util.Datetime(loadBalancer.Created)
			})).
			AddFieldFn("age", output.FieldFn(func(obj interface{}) string {
				loadBalancer := obj.(*hcloud.LoadBalancer)
				return util.Age(loadBalancer.Created, time.Now())
			}))
	},

	JSONSchema: func(resources []interface{}) interface{} {
		var loadBalancerSchemas []schema.LoadBalancer
		for _, resource := range resources {
			loadBalancer := resource.(*hcloud.LoadBalancer)
			loadBalancerSchema := schema.LoadBalancer{
				ID:   loadBalancer.ID,
				Name: loadBalancer.Name,
				PublicNet: schema.LoadBalancerPublicNet{
					Enabled: loadBalancer.PublicNet.Enabled,
					IPv4: schema.LoadBalancerPublicNetIPv4{
						IP: loadBalancer.PublicNet.IPv4.IP.String(),
					},
					IPv6: schema.LoadBalancerPublicNetIPv6{
						IP: loadBalancer.PublicNet.IPv6.IP.String(),
					},
				},
				Created:          loadBalancer.Created,
				Labels:           loadBalancer.Labels,
				LoadBalancerType: util.LoadBalancerTypeToSchema(*loadBalancer.LoadBalancerType),
				Location:         util.LocationToSchema(*loadBalancer.Location),
				IncludedTraffic:  loadBalancer.IncludedTraffic,
				OutgoingTraffic:  &loadBalancer.OutgoingTraffic,
				IngoingTraffic:   &loadBalancer.IngoingTraffic,
				Protection: schema.LoadBalancerProtection{
					Delete: loadBalancer.Protection.Delete,
				},
				Algorithm: schema.LoadBalancerAlgorithm{Type: string(loadBalancer.Algorithm.Type)},
			}
			for _, service := range loadBalancer.Services {
				serviceSchema := schema.LoadBalancerService{
					Protocol:        string(service.Protocol),
					ListenPort:      service.ListenPort,
					DestinationPort: service.DestinationPort,
					Proxyprotocol:   service.Proxyprotocol,
					HealthCheck: &schema.LoadBalancerServiceHealthCheck{
						Protocol: string(service.HealthCheck.Protocol),
						Port:     service.HealthCheck.Port,
						Interval: int(service.HealthCheck.Interval.Seconds()),
						Timeout:  int(service.HealthCheck.Timeout.Seconds()),
						Retries:  service.HealthCheck.Retries,
					},
				}
				if service.Protocol != hcloud.LoadBalancerServiceProtocolTCP {
					serviceSchema.HTTP = &schema.LoadBalancerServiceHTTP{
						StickySessions: service.HTTP.StickySessions,
						CookieName:     service.HTTP.CookieName,
						CookieLifetime: int(service.HTTP.CookieLifetime.Seconds()),
						RedirectHTTP:   service.HTTP.RedirectHTTP,
					}
				}
				if service.HealthCheck.HTTP != nil {
					serviceSchema.HealthCheck.HTTP = &schema.LoadBalancerServiceHealthCheckHTTP{
						Domain:      service.HealthCheck.HTTP.Domain,
						Path:        service.HealthCheck.HTTP.Path,
						StatusCodes: service.HealthCheck.HTTP.StatusCodes,
						TLS:         service.HealthCheck.HTTP.TLS,
						Response:    service.HealthCheck.HTTP.Response,
					}
				}
				loadBalancerSchema.Services = append(loadBalancerSchema.Services, serviceSchema)
			}
			for _, target := range loadBalancer.Targets {
				targetSchema := schema.LoadBalancerTarget{
					Type:         string(target.Type),
					UsePrivateIP: target.UsePrivateIP,
				}
				if target.Type == hcloud.LoadBalancerTargetTypeServer {
					targetSchema.Server = &schema.LoadBalancerTargetServer{ID: target.Server.Server.ID}
				}
				if target.Type == hcloud.LoadBalancerTargetTypeLabelSelector {
					targetSchema.LabelSelector = &schema.LoadBalancerTargetLabelSelector{Selector: target.LabelSelector.Selector}
				}
				if target.Type == hcloud.LoadBalancerTargetTypeIP {
					targetSchema.IP = &schema.LoadBalancerTargetIP{IP: target.IP.IP}
				}
				for _, healthStatus := range target.HealthStatus {
					targetSchema.HealthStatus = append(targetSchema.HealthStatus, schema.LoadBalancerTargetHealthStatus{
						ListenPort: healthStatus.ListenPort,
						Status:     string(healthStatus.Status),
					})
				}
				loadBalancerSchema.Targets = append(loadBalancerSchema.Targets, targetSchema)
			}

			loadBalancerSchemas = append(loadBalancerSchemas, loadBalancerSchema)
		}
		return loadBalancerSchemas
	},
}
View Source
var MetricsCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "metrics [FLAGS] LOADBALANCER",
			Short:                 "[ALPHA] Metrics from a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("type", "", "Type of metrics you want to show")
		cmd.MarkFlagRequired("type")
		cmd.RegisterFlagCompletionFunc("type", cmpl.SuggestCandidates("open_connections", "connections_per_second", "requests_per_second", "bandwidth"))

		cmd.Flags().String("start", "", "ISO 8601 timestamp")
		cmd.Flags().String("end", "", "ISO 8601 timestamp")

		output.AddFlag(cmd, output.OptionJSON())
		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		outputFlags := output.FlagsForCommand(cmd)

		idOrName := args[0]
		LoadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if LoadBalancer == nil {
			return fmt.Errorf("LoadBalancer not found: %s", idOrName)
		}

		metricType, _ := cmd.Flags().GetString("type")

		start, _ := cmd.Flags().GetString("start")
		startTime := time.Now().Add(-30 * time.Minute)
		if start != "" {
			startTime, err = time.Parse(time.RFC3339, start)
			if err != nil {
				return fmt.Errorf("start date has an invalid format. It should be ISO 8601, like: %s", time.Now().Format(time.RFC3339))
			}
		}

		end, _ := cmd.Flags().GetString("end")
		endTime := time.Now()
		if end != "" {
			endTime, err = time.Parse(time.RFC3339, end)
			if err != nil {
				return fmt.Errorf("end date has an invalid format. It should be ISO 8601, like: %s", time.Now().Format(time.RFC3339))
			}
		}

		m, resp, err := client.LoadBalancer().GetMetrics(ctx, LoadBalancer, hcloud.LoadBalancerGetMetricsOpts{
			Types: []hcloud.LoadBalancerMetricType{hcloud.LoadBalancerMetricType(metricType)},
			Start: startTime,
			End:   endTime,
		})

		if err != nil {
			return err
		}
		switch {
		case outputFlags.IsSet("json"):
			var data map[string]interface{}
			if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
				return err
			}
			return util.DescribeJSON(data)
		default:
			var keys []string
			for k := range m.TimeSeries {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				if len(m.TimeSeries[k]) == 0 {
					fmt.Printf("Currently there are now metrics available. Please try it again later.")
					return nil
				}
				fmt.Printf("Load Balancer: %s \t Metric: %s \t Start: %s \t End: %s\n", LoadBalancer.Name, k, m.Start.String(), m.End.String())
				var data []float64
				for _, m := range m.TimeSeries[k] {
					d, _ := strconv.ParseFloat(m.Value, 64)
					data = append(data, d)
				}
				graph := asciigraph.Plot(data, asciigraph.Height(20), asciigraph.Width(100))
				fmt.Println(graph)
				fmt.Printf("\n\n")
			}
		}
		return nil
	},
}
View Source
var RemoveTargetCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "remove-target LOADBALANCER FLAGS",
			Short:                 "Remove a target to a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("server", "", "Name or ID of the server")
		cmd.RegisterFlagCompletionFunc("server", cmpl.SuggestCandidatesF(client.Server().Names))

		cmd.Flags().String("label-selector", "", "Label Selector")

		cmd.Flags().String("ip", "", "IP address of an IP target")

		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		var (
			action       *hcloud.Action
			loadBalancer *hcloud.LoadBalancer
			err          error
		)

		serverIDOrName, _ := cmd.Flags().GetString("server")
		labelSelector, _ := cmd.Flags().GetString("label-selector")
		ipAddr, _ := cmd.Flags().GetString("ip")

		idOrName := args[0]

		loadBalancer, _, err = client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		if !util.ExactlyOneSet(serverIDOrName, labelSelector, ipAddr) {
			return fmt.Errorf("--server, --label-selector, and --ip are mutually exclusive")
		}
		switch {
		case serverIDOrName != "":
			server, _, err := client.Server().Get(ctx, serverIDOrName)
			if err != nil {
				return err
			}
			if server == nil {
				return fmt.Errorf("server not found: %s", serverIDOrName)
			}
			action, _, err = client.LoadBalancer().RemoveServerTarget(ctx, loadBalancer, server)
			if err != nil {
				return err
			}
		case labelSelector != "":
			action, _, err = client.LoadBalancer().RemoveLabelSelectorTarget(ctx, loadBalancer, labelSelector)
			if err != nil {
				return err
			}
		case ipAddr != "":
			ip := net.ParseIP(ipAddr)
			if ip == nil {
				return fmt.Errorf("invalid ip provided")
			}
			if action, _, err = client.LoadBalancer().RemoveIPTarget(ctx, loadBalancer, ip); err != nil {
				return err
			}
		default:
			return fmt.Errorf("specify one of --server, --label-selector, or --ip")
		}

		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}
		fmt.Printf("Target removed from Load Balancer %d\n", loadBalancer.ID)

		return nil
	},
}
View Source
var UpdateServiceCommand = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "update-service LOADBALANCER FLAGS",
			Short:                 "Updates a service from a Load Balancer",
			Args:                  cobra.ExactArgs(1),
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().Int("listen-port", 0, "The listen port of the service that you want to update (required)")
		cmd.MarkFlagRequired("listen-port")

		cmd.Flags().Int("destination-port", 0, "Destination port of the service on the targets")

		cmd.Flags().String("protocol", "", "The protocol the health check is performed over")
		cmd.Flags().Bool("proxy-protocol", false, "Enable or disable (with --proxy-protocol=false) Proxy Protocol")
		cmd.Flags().Bool("http-redirect-http", false, "Enable or disable redirect all traffic on port 80 to port 443")

		cmd.Flags().Bool("http-sticky-sessions", false, "Enable or disable (with --http-sticky-sessions=false) Sticky Sessions")
		cmd.Flags().String("http-cookie-name", "", "Sticky Sessions: Cookie Name which will be set")
		cmd.Flags().Duration("http-cookie-lifetime", 0, "Sticky Sessions: Lifetime of the cookie")
		cmd.Flags().Int64Slice("http-certificates", []int64{}, "ID of Certificates which are attached to this Load Balancer")

		cmd.Flags().String("health-check-protocol", "", "The protocol the health check is performed over")
		cmd.Flags().Int("health-check-port", 0, "The port the health check is performed over")
		cmd.Flags().Duration("health-check-interval", 15*time.Second, "The interval the health check is performed")
		cmd.Flags().Duration("health-check-timeout", 10*time.Second, "The timeout after a health check is marked as failed")
		cmd.Flags().Int("health-check-retries", 3, "Number of retries after a health check is marked as failed")

		cmd.Flags().String("health-check-http-domain", "", "The domain we request when performing a http health check")
		cmd.Flags().String("health-check-http-path", "", "The path we request when performing a http health check")

		cmd.Flags().StringSlice("health-check-http-status-codes", []string{}, "List of status codes we expect to determine a target as healthy")
		cmd.Flags().String("health-check-http-response", "", "The response we expect to determine a target as healthy")
		cmd.Flags().Bool("health-check-http-tls", false, "Determine if the health check should verify if the target answers with a valid TLS certificate")
		return cmd
	},
	Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		listenPort, _ := cmd.Flags().GetInt("listen-port")

		loadBalancer, _, err := client.LoadBalancer().Get(ctx, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}
		var service hcloud.LoadBalancerService
		for _, _service := range loadBalancer.Services {
			if _service.ListenPort == listenPort {
				if _service.HealthCheck.HTTP != nil {
					service = _service
				}
			}
		}
		opts := hcloud.LoadBalancerUpdateServiceOpts{
			HTTP:        &hcloud.LoadBalancerUpdateServiceOptsHTTP{},
			HealthCheck: &hcloud.LoadBalancerUpdateServiceOptsHealthCheck{},
		}
		if cmd.Flag("protocol").Changed {
			protocol, _ := cmd.Flags().GetString("protocol")
			opts.Protocol = hcloud.LoadBalancerServiceProtocol(protocol)
		}
		if cmd.Flag("destination-port").Changed {
			destinationPort, _ := cmd.Flags().GetInt("destination-port")
			opts.DestinationPort = &destinationPort
		}
		if cmd.Flag("proxy-protocol").Changed {
			proxyProtocol, _ := cmd.Flags().GetBool("proxy-protocol")
			opts.Proxyprotocol = hcloud.Bool(proxyProtocol)
		}

		if cmd.Flag("http-redirect-http").Changed {
			redirectHTTP, _ := cmd.Flags().GetBool("http-redirect-http")
			opts.HTTP.RedirectHTTP = hcloud.Bool(redirectHTTP)
		}
		if cmd.Flag("http-sticky-sessions").Changed {
			stickySessions, _ := cmd.Flags().GetBool("http-sticky-sessions")
			opts.HTTP.StickySessions = hcloud.Bool(stickySessions)
		}
		if cmd.Flag("http-cookie-name").Changed {
			cookieName, _ := cmd.Flags().GetString("http-cookie-name")
			opts.HTTP.CookieName = hcloud.String(cookieName)
		}
		if cmd.Flag("http-cookie-lifetime").Changed {
			cookieLifetime, _ := cmd.Flags().GetDuration("http-cookie-lifetime")
			opts.HTTP.CookieLifetime = hcloud.Duration(cookieLifetime)
		}
		if cmd.Flag("http-certificates").Changed {
			certificates, _ := cmd.Flags().GetInt64Slice("http-certificates")
			for _, certificateID := range certificates {
				opts.HTTP.Certificates = append(opts.HTTP.Certificates, &hcloud.Certificate{ID: certificateID})
			}
		}

		if cmd.Flag("health-check-protocol").Changed {
			healthCheckProtocol, _ := cmd.Flags().GetString("health-check-protocol")
			opts.HealthCheck.Protocol = hcloud.LoadBalancerServiceProtocol(healthCheckProtocol)
		}
		if cmd.Flag("health-check-port").Changed {
			healthCheckPort, _ := cmd.Flags().GetInt("health-check-port")
			opts.HealthCheck.Port = hcloud.Int(healthCheckPort)
		}
		if cmd.Flag("health-check-interval").Changed {
			healthCheckInterval, _ := cmd.Flags().GetDuration("health-check-interval")
			opts.HealthCheck.Interval = hcloud.Duration(healthCheckInterval)
		}
		if cmd.Flag("health-check-timeout").Changed {
			healthCheckTimeout, _ := cmd.Flags().GetDuration("health-check-timeout")
			opts.HealthCheck.Timeout = hcloud.Duration(healthCheckTimeout)
		}
		if cmd.Flag("health-check-retries").Changed {
			healthCheckRetries, _ := cmd.Flags().GetInt("health-check-retries")
			opts.HealthCheck.Retries = hcloud.Int(healthCheckRetries)
		}

		healthCheckProtocol, _ := cmd.Flags().GetString("health-check-protocol")
		if healthCheckProtocol != string(hcloud.LoadBalancerServiceProtocolTCP) || service.HealthCheck.Protocol != hcloud.LoadBalancerServiceProtocolTCP {
			opts.HealthCheck.HTTP = &hcloud.LoadBalancerUpdateServiceOptsHealthCheckHTTP{}

			if cmd.Flag("health-check-http-domain").Changed {
				healthCheckHTTPDomain, _ := cmd.Flags().GetString("health-check-http-domain")
				opts.HealthCheck.HTTP.Domain = hcloud.String(healthCheckHTTPDomain)
			}
			if cmd.Flag("health-check-http-path").Changed {
				healthCheckHTTPPath, _ := cmd.Flags().GetString("health-check-http-path")
				opts.HealthCheck.HTTP.Path = hcloud.String(healthCheckHTTPPath)
			}
			if cmd.Flag("health-check-http-response").Changed {
				healthCheckHTTPResponse, _ := cmd.Flags().GetString("health-check-http-response")
				opts.HealthCheck.HTTP.Response = hcloud.String(healthCheckHTTPResponse)
			}
			if cmd.Flag("health-check-http-status-codes").Changed {
				healthCheckHTTPStatusCodes, _ := cmd.Flags().GetStringSlice("health-check-http-status-codes")
				opts.HealthCheck.HTTP.StatusCodes = healthCheckHTTPStatusCodes
			}
			if cmd.Flag("health-check-http-tls").Changed {
				healthCheckHTTPTLS, _ := cmd.Flags().GetBool("health-check-http-tls")
				opts.HealthCheck.HTTP.TLS = hcloud.Bool(healthCheckHTTPTLS)
			}
		}

		action, _, err := client.LoadBalancer().UpdateService(ctx, loadBalancer, listenPort, opts)
		if err != nil {
			return err
		}
		if err := waiter.ActionProgress(ctx, action); err != nil {
			return err
		}
		fmt.Printf("Service %d on Load Balancer %d was updated\n", listenPort, loadBalancer.ID)

		return nil
	},
}

Functions

func NewCommand

func NewCommand(cli *state.State, client hcapi2.Client) *cobra.Command

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL