loadbalancer

package
v1.56.0 Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2025 License: MIT Imports: 23 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AddServiceCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "add-service [options] (--protocol http | --protocol tcp --listen-port <1-65535> --destination-port <1-65535> | --protocol https --http-certificates <ids>) <load-balancer>",
			Short:                 "Add a service to a Load Balancer",
			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 (true, false)")

		cmd.Flags().Bool("http-sticky-sessions", false, "Enable Sticky Sessions (true, false)")
		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().StringSlice("http-certificates", []string{}, "IDs or names of Certificates which should be attached to this Load Balancer")
		cmd.Flags().Bool("http-redirect-http", false, "Redirect all traffic on port 80 to port 443 (true, false)")

		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 (true, false)")

		return cmd
	},
	Run: func(s state.State, 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().GetStringSlice("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")
			}
		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 := s.Client().LoadBalancer().Get(s, 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: &proxyProtocol,
		}

		if listenPort != 0 {
			opts.ListenPort = &listenPort
		}
		if destinationPort != 0 {
			opts.DestinationPort = &destinationPort
		}

		if protocol != string(hcloud.LoadBalancerServiceProtocolTCP) {
			opts.HTTP = &hcloud.LoadBalancerAddServiceOptsHTTP{
				StickySessions: &httpStickySessions,
				RedirectHTTP:   &httpRedirect,
			}
			if httpCookieName != "" {
				opts.HTTP.CookieName = &httpCookieName
			}
			if httpCookieLifetime != 0 {
				opts.HTTP.CookieLifetime = &httpCookieLifetime
			}
			for _, idOrName := range httpCertificates {
				cert, _, err := s.Client().Certificate().Get(s, idOrName)
				if err != nil {
					return err
				}
				opts.HTTP.Certificates = append(opts.HTTP.Certificates, cert)
			}
		}

		healthCheckProtocol, _ := cmd.Flags().GetString("health-check-protocol")
		healthCheckPort, _ := cmd.Flags().GetInt("health-check-port")
		healthCheckInterval, _ := cmd.Flags().GetDuration("health-check-interval")
		healthCheckTimeout, _ := cmd.Flags().GetDuration("health-check-timeout")
		healthCheckRetries, _ := cmd.Flags().GetInt("health-check-retries")

		addHealthCheck := false
		for _, f := range []string{"protocol", "port", "interval", "timeout", "retries"} {
			if cmd.Flags().Changed("health-check-" + f) {
				addHealthCheck = true
				break
			}
		}

		if addHealthCheck {
			opts.HealthCheck = &hcloud.LoadBalancerAddServiceOptsHealthCheck{}
			if healthCheckProtocol == "" {
				return fmt.Errorf("required flag health-check-protocol not set")
			}
			switch proto := hcloud.LoadBalancerServiceProtocol(healthCheckProtocol); proto {
			case hcloud.LoadBalancerServiceProtocolHTTP, hcloud.LoadBalancerServiceProtocolHTTPS, hcloud.LoadBalancerServiceProtocolTCP:
				opts.HealthCheck.Protocol = proto
			default:
				return fmt.Errorf("invalid health check protocol: %s", healthCheckProtocol)
			}

			if healthCheckPort == 0 {
				return fmt.Errorf("required flag health-check-port not set")
			}
			if healthCheckPort > 65535 {
				return fmt.Errorf("invalid health check port: %d", healthCheckPort)
			}
			opts.HealthCheck.Port = &healthCheckPort

			if cmd.Flags().Changed("health-check-interval") {
				opts.HealthCheck.Interval = &healthCheckInterval
			}
			if cmd.Flags().Changed("health-check-timeout") {
				opts.HealthCheck.Timeout = &healthCheckTimeout
			}
			if cmd.Flags().Changed("health-check-retries") {
				opts.HealthCheck.Retries = &healthCheckRetries
			}

			if opts.HealthCheck.Protocol == hcloud.LoadBalancerServiceProtocolHTTP ||
				opts.HealthCheck.Protocol == hcloud.LoadBalancerServiceProtocolHTTPS {

				opts.HealthCheck.HTTP = &hcloud.LoadBalancerAddServiceOptsHealthCheckHTTP{}
				healthCheckHTTPDomain, _ := cmd.Flags().GetString("health-check-http-domain")
				healthCheckHTTPPath, _ := cmd.Flags().GetString("health-check-http-path")
				healthCheckHTTPResponse, _ := cmd.Flags().GetString("health-check-http-response")
				healthCheckHTTPStatusCodes, _ := cmd.Flags().GetStringSlice("health-check-http-status-codes")
				healthCheckHTTPTLS, _ := cmd.Flags().GetBool("health-check-http-tls")

				if cmd.Flags().Changed("health-check-http-domain") {
					opts.HealthCheck.HTTP.Domain = &healthCheckHTTPDomain
				}
				if cmd.Flags().Changed("health-check-http-path") {
					opts.HealthCheck.HTTP.Path = &healthCheckHTTPPath
				}
				if cmd.Flags().Changed("health-check-http-response") {
					opts.HealthCheck.HTTP.Response = &healthCheckHTTPResponse
				}
				if cmd.Flags().Changed("health-check-http-status-codes") {
					opts.HealthCheck.HTTP.StatusCodes = healthCheckHTTPStatusCodes
				}
				if cmd.Flags().Changed("health-check-http-tls") {
					opts.HealthCheck.HTTP.TLS = &healthCheckHTTPTLS
				}
			}
		}

		action, _, err := s.Client().LoadBalancer().AddService(s, loadBalancer, opts)
		if err != nil {
			return err
		}
		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}
		cmd.Printf("Service was added to Load Balancer %d\n", loadBalancer.ID)

		return nil
	},
}
View Source
var AddTargetCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "add-target [options] (--server <server> | --label-selector <label-selector> | --ip <ip>) <load-balancer>",
			Short:                 "Add a target to a Load Balancer",
			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 (true, false)")
		cmd.Flags().String("ip", "", "Use the passed IP address as target")
		return cmd
	},
	Run: func(s state.State, 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.AnySet(serverIDOrName, labelSelector, ipAddr) {
			return fmt.Errorf("specify one of --server, --label-selector, or --ip")
		}
		if !util.ExactlyOneSet(serverIDOrName, labelSelector, ipAddr) {
			return fmt.Errorf("--server, --label-selector, and --ip are mutually exclusive")
		}
		if loadBalancer, _, err = s.Client().LoadBalancer().Get(s, idOrName); err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

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

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

		return nil
	},
}
View Source
var AttachToNetworkCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "attach-to-network [--ip <ip>] --network <network> <load-balancer>",
			Short:                 "Attach a Load Balancer to a Network",
			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)")
		cmd.Flags().IPNet("ip-range", net.IPNet{}, "IP range in CIDR block notation of the subnet to attach to (auto-assigned if omitted)")

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, 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 := s.Client().Network().Get(s, networkIDOrName)
		if err != nil {
			return err
		}
		if network == nil {
			return fmt.Errorf("Network not found: %s", networkIDOrName)
		}

		ip, _ := cmd.Flags().GetIP("ip")
		ipRange, _ := cmd.Flags().GetIPNet("ip-range")

		opts := hcloud.LoadBalancerAttachToNetworkOpts{
			Network: network,
			IP:      ip,
		}
		if cmd.Flags().Changed("ip-range") {
			opts.IPRange = &ipRange
		}
		action, _, err := s.Client().LoadBalancer().AttachToNetwork(s, loadBalancer, opts)

		if err != nil {
			return err
		}

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

		cmd.Printf("Load Balancer %d attached to Network %d\n", loadBalancer.ID, network.ID)
		return nil
	},
}
View Source
var ChangeAlgorithmCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "change-algorithm --algorithm-type <round_robin|least_connections> <load-balancer>",
			Short:                 "Changes the algorithm of a Load Balancer",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().String("algorithm-type", "", "New Load Balancer algorithm (round_robin, least_connections) (required)")
		_ = cmd.RegisterFlagCompletionFunc("algorithm-type", cmpl.SuggestCandidates(
			string(hcloud.LoadBalancerAlgorithmTypeRoundRobin),
			string(hcloud.LoadBalancerAlgorithmTypeLeastConnections),
		))
		_ = cmd.MarkFlagRequired("algorithm-type")

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

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

		return nil
	},
}
View Source
var ChangeTypeCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:   "change-type <load-balancer> <load-balancer-type>",
			Short: "Change type of a Load Balancer",
			ValidArgsFunction: cmpl.SuggestArgs(
				cmpl.SuggestCandidatesF(client.LoadBalancer().Names),
				cmpl.SuggestCandidatesF(client.LoadBalancerType().Names),
			),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		loadBalancerTypeIDOrName := args[1]
		loadBalancerType, _, err := s.Client().LoadBalancerType().Get(s, 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 := s.Client().LoadBalancer().ChangeType(s, loadBalancer, opts)
		if err != nil {
			return err
		}

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

		cmd.Printf("Load Balancer %d changed to type %s\n", loadBalancer.ID, loadBalancerType.Name)
		return nil
	},
}
View Source
var CreateCmd = base.CreateCmd[*hcloud.LoadBalancer]{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "create [options] --name <name> --type <type>",
			Short:                 "Create a Load Balancer",
			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)")

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

		cmd.Flags().String("network", "", "Name or ID of the Network the Load Balancer should be attached to on creation")
		_ = cmd.RegisterFlagCompletionFunc("network", cmpl.SuggestCandidatesF(client.Network().Names))

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, _ []string) (*hcloud.LoadBalancer, any, 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")
		protection, _ := cmd.Flags().GetStringSlice("enable-protection")
		network, _ := cmd.Flags().GetString("network")

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

		createOpts := hcloud.LoadBalancerCreateOpts{
			Name: name,
			LoadBalancerType: &hcloud.LoadBalancerType{
				Name: serverType,
			},
			Labels: labels,
		}
		if algorithmType != "" {
			createOpts.Algorithm = &hcloud.LoadBalancerAlgorithm{Type: hcloud.LoadBalancerAlgorithmType(algorithmType)}
		}
		if networkZone != "" {
			createOpts.NetworkZone = hcloud.NetworkZone(networkZone)
		}
		if location != "" {
			createOpts.Location = &hcloud.Location{Name: location}
		}
		if network != "" {
			net, _, err := s.Client().Network().Get(s, network)
			if err != nil {
				return nil, nil, err
			}
			if net == nil {
				return nil, nil, fmt.Errorf("Network not found: %s", network)
			}
			createOpts.Network = net
		}
		result, _, err := s.Client().LoadBalancer().Create(s, createOpts)
		if err != nil {
			return nil, nil, err
		}

		if err := s.WaitForActions(s, cmd, result.Action); err != nil {
			return nil, nil, err
		}
		cmd.Printf("Load Balancer %d created\n", result.LoadBalancer.ID)

		if err := changeProtection(s, cmd, result.LoadBalancer, true, protectionOpts); err != nil {
			return nil, nil, err
		}

		loadBalancer, _, err := s.Client().LoadBalancer().GetByID(s, result.LoadBalancer.ID)
		if err != nil {
			return nil, nil, err
		}
		if loadBalancer == nil {
			return nil, nil, fmt.Errorf("Load Balancer not found: %d", result.LoadBalancer.ID)
		}

		return loadBalancer, util.Wrap("load_balancer", hcloud.SchemaFromLoadBalancer(loadBalancer)), nil
	},

	PrintResource: func(_ state.State, cmd *cobra.Command, loadBalancer *hcloud.LoadBalancer) {
		cmd.Printf("IPv4: %s\n", loadBalancer.PublicNet.IPv4.IP.String())
		cmd.Printf("IPv6: %s\n", loadBalancer.PublicNet.IPv6.IP.String())
	},
}
View Source
var DeleteCmd = base.DeleteCmd{
	ResourceNameSingular: "Load Balancer",
	ResourceNamePlural:   "Load Balancers",
	ShortDescription:     "Delete a Load Balancer",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
	Fetch: func(s state.State, _ *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
		return s.Client().LoadBalancer().Get(s, idOrName)
	},
	Delete: func(s state.State, _ *cobra.Command, resource interface{}) (*hcloud.Action, error) {
		loadBalancer := resource.(*hcloud.LoadBalancer)
		_, err := s.Client().LoadBalancer().Delete(s, loadBalancer)
		return nil, err
	},
}
View Source
var DeleteServiceCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "delete-service --listen-port <1-65535> <load-balancer>",
			Short:                 "Deletes a service from a Load Balancer",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			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(s state.State, cmd *cobra.Command, args []string) error {
		listenPort, _ := cmd.Flags().GetInt("listen-port")
		idOrName := args[0]
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}
		_, _, err = s.Client().LoadBalancer().DeleteService(s, loadBalancer, listenPort)
		if err != nil {
			return err
		}

		cmd.Printf("Service on port %d deleted from Load Balancer %d\n", listenPort, loadBalancer.ID)
		return nil
	},
}
View Source
var DescribeCmd = base.DescribeCmd[*hcloud.LoadBalancer]{
	ResourceNameSingular: "Load Balancer",
	ShortDescription:     "Describe a Load Balancer",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
	Fetch: func(s state.State, _ *cobra.Command, idOrName string) (*hcloud.LoadBalancer, any, error) {
		lb, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return nil, nil, err
		}
		return lb, hcloud.SchemaFromLoadBalancer(lb), nil
	},
	AdditionalFlags: func(cmd *cobra.Command) {
		cmd.Flags().Bool("expand-targets", false, "Expand all label_selector targets (true, false)")
	},
	PrintText: func(s state.State, cmd *cobra.Command, out io.Writer, loadBalancer *hcloud.LoadBalancer) error {
		withLabelSelectorTargets, _ := cmd.Flags().GetBool("expand-targets")

		fmt.Fprintf(out, "ID:\t%d\n", loadBalancer.ID)
		fmt.Fprintf(out, "Name:\t%s\n", loadBalancer.Name)
		fmt.Fprintf(out, "Created:\t%s (%s)\n", util.Datetime(loadBalancer.Created), humanize.Time(loadBalancer.Created))
		fmt.Fprintf(out, "Algorithm:\t%s\n", loadBalancer.Algorithm.Type)

		fmt.Fprintln(out)
		fmt.Fprintf(out, "Public Net:\n")
		fmt.Fprintf(out, "  Enabled:\t%s\n", util.YesNo(loadBalancer.PublicNet.Enabled))
		fmt.Fprintf(out, "  IPv4:\t%s\n", loadBalancer.PublicNet.IPv4.IP.String())
		fmt.Fprintf(out, "  IPv4 DNS PTR:\t%s\n", loadBalancer.PublicNet.IPv4.DNSPtr)
		fmt.Fprintf(out, "  IPv6:\t%s\n", loadBalancer.PublicNet.IPv6.IP.String())
		fmt.Fprintf(out, "  IPv6 DNS PTR:\t%s\n", loadBalancer.PublicNet.IPv6.DNSPtr)

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

		fmt.Fprintln(out)
		fmt.Fprintf(out, "Load Balancer Type:\n")
		fmt.Fprintf(out, "%s", util.PrefixLines(loadbalancertype.DescribeLoadBalancerType(s, loadBalancer.LoadBalancerType, true), "  "))

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

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

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

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

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

		fmt.Fprintln(out)
		util.DescribeLabels(out, loadBalancer.Labels, "")

		return nil
	},
}

DescribeCmd defines a command for describing a LoadBalancer.

View Source
var DetachFromNetworkCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "detach-from-network --network <network> <load-balancer>",
			Short:                 "Detach a Load Balancer from a Network",
			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(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, 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 := s.Client().Network().Get(s, networkIDOrName)
		if err != nil {
			return err
		}
		if network == nil {
			return fmt.Errorf("Network not found: %s", networkIDOrName)
		}

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

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

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

		opts, err := getChangeProtectionOpts(false, args[1:])
		if err != nil {
			return err
		}

		return changeProtection(s, cmd, loadBalancer, false, opts)
	},
}
View Source
var DisablePublicInterfaceCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:                   "disable-public-interface <load-balancer>",
			Short:                 "Disable the public interface of a Load Balancer",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

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

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

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

		opts, err := getChangeProtectionOpts(true, args[1:])
		if err != nil {
			return err
		}

		return changeProtection(s, cmd, loadBalancer, true, opts)
	},
}
View Source
var EnablePublicInterfaceCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		return &cobra.Command{
			Use:                   "enable-public-interface <load-balancer>",
			Short:                 "Enable the public interface of a Load Balancer",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

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

		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}

		cmd.Printf("Public interface of Load Balancer %d was enabled\n", loadBalancer.ID)
		return nil
	},
}
View Source
var LabelCmds = base.LabelCmds[*hcloud.LoadBalancer]{
	ResourceNameSingular:   "Load Balancer",
	ShortDescriptionAdd:    "Add a label to a Load Balancer",
	ShortDescriptionRemove: "Remove a label from a Load Balancer",
	NameSuggestions:        func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
	LabelKeySuggestions:    func(c hcapi2.Client) func(idOrName string) []string { return c.LoadBalancer().LabelKeys },
	Fetch: func(s state.State, idOrName string) (*hcloud.LoadBalancer, error) {
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return nil, err
		}
		if loadBalancer == nil {
			return nil, fmt.Errorf("Load Balancer not found: %s", idOrName)
		}
		return loadBalancer, nil
	},
	SetLabels: func(s state.State, loadBalancer *hcloud.LoadBalancer, labels map[string]string) error {
		opts := hcloud.LoadBalancerUpdateOpts{
			Labels: labels,
		}
		_, _, err := s.Client().LoadBalancer().Update(s, loadBalancer, opts)
		return err
	},
	GetLabels: func(loadBalancer *hcloud.LoadBalancer) map[string]string {
		return loadBalancer.Labels
	},
	GetIDOrName: func(loadBalancer *hcloud.LoadBalancer) string {
		return strconv.FormatInt(loadBalancer.ID, 10)
	},
}
View Source
var ListCmd = &base.ListCmd[*hcloud.LoadBalancer, schema.LoadBalancer]{
	ResourceNamePlural: "Load Balancer",
	JSONKeyGetByName:   "load_balancers",
	DefaultColumns:     []string{"id", "name", "health", "ipv4", "ipv6", "type", "location", "network_zone", "age"},
	SortOption:         config.OptionSortLoadBalancer,

	Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]*hcloud.LoadBalancer, error) {
		opts := hcloud.LoadBalancerListOpts{ListOpts: listOpts}
		if len(sorts) > 0 {
			opts.Sort = sorts
		}
		return s.Client().LoadBalancer().AllWithOpts(s, opts)
	},

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

	Schema: hcloud.SchemaFromLoadBalancer,
}
View Source
var MetricsCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   fmt.Sprintf("metrics [options] (--type <%s>)... <load-balancer>", strings.Join(metricTypeStrings, "|")),
			Short:                 "[ALPHA] Metrics from a Load Balancer",
			ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(client.LoadBalancer().Names)),
			TraverseChildren:      true,
			DisableFlagsInUseLine: true,
		}

		cmd.Flags().StringSlice("type", nil, "Types of metrics you want to show")
		_ = cmd.MarkFlagRequired("type")
		_ = cmd.RegisterFlagCompletionFunc("type", cmpl.SuggestCandidates(metricTypeStrings...))

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

		output.AddFlag(cmd, output.OptionJSON(), output.OptionYAML())
		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		outputFlags := output.FlagsForCommand(cmd)

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

		metricTypesStr, _ := cmd.Flags().GetStringSlice("type")
		var metricTypes []hcloud.LoadBalancerMetricType
		for _, t := range metricTypesStr {
			if slices.Contains(metricTypeStrings, t) {
				metricTypes = append(metricTypes, hcloud.LoadBalancerMetricType(t))
			} else {
				return fmt.Errorf("invalid metric type: %s", t)
			}
		}

		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 := s.Client().LoadBalancer().GetMetrics(s, LoadBalancer, hcloud.LoadBalancerGetMetricsOpts{
			Types: metricTypes,
			Start: startTime,
			End:   endTime,
		})

		if err != nil {
			return err
		}
		switch {
		case outputFlags.IsSet("json") || outputFlags.IsSet("yaml"):
			var schema map[string]interface{}
			if err := json.NewDecoder(resp.Body).Decode(&schema); err != nil {
				return err
			}
			if outputFlags.IsSet("json") {
				return util.DescribeJSON(cmd.OutOrStdout(), schema)
			}
			return util.DescribeYAML(cmd.OutOrStdout(), schema)
		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 {
					cmd.Printf("Currently there are no metrics available. Please try it again later.")
					return nil
				}
				cmd.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))
				cmd.Println(graph)
				cmd.Printf("\n\n")
			}
		}
		return nil
	},
}
View Source
var RemoveTargetCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "remove-target [options] <load-balancer>",
			Short:                 "Remove a target from a Load Balancer",
			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(s state.State, 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 = s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return err
		}
		if loadBalancer == nil {
			return fmt.Errorf("Load Balancer not found: %s", idOrName)
		}

		if !util.AnySet(serverIDOrName, labelSelector, ipAddr) {
			return fmt.Errorf("specify one of --server, --label-selector, or --ip")
		}
		if !util.ExactlyOneSet(serverIDOrName, labelSelector, ipAddr) {
			return fmt.Errorf("--server, --label-selector, and --ip are mutually exclusive")
		}
		switch {
		case serverIDOrName != "":
			server, _, err := s.Client().Server().Get(s, serverIDOrName)
			if err != nil {
				return err
			}
			if server == nil {
				return fmt.Errorf("server not found: %s", serverIDOrName)
			}
			action, _, err = s.Client().LoadBalancer().RemoveServerTarget(s, loadBalancer, server)
			if err != nil {
				return err
			}
		case labelSelector != "":
			action, _, err = s.Client().LoadBalancer().RemoveLabelSelectorTarget(s, 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 = s.Client().LoadBalancer().RemoveIPTarget(s, loadBalancer, ip); err != nil {
				return err
			}
		default:
			return fmt.Errorf("specify one of --server, --label-selector, or --ip")
		}

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

		return nil
	},
}
View Source
var SetRDNSCmd = base.SetRdnsCmd{
	ResourceNameSingular: "Load Balancer",
	ShortDescription:     "Change reverse DNS of a Load Balancer",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
	Fetch: func(s state.State, _ *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
		return s.Client().LoadBalancer().Get(s, idOrName)
	},
	GetDefaultIP: func(resource interface{}) net.IP {
		loadBalancer := resource.(*hcloud.LoadBalancer)
		return loadBalancer.PublicNet.IPv4.IP
	},
}
View Source
var UpdateCmd = base.UpdateCmd{
	ResourceNameSingular: "Load Balancer",
	ShortDescription:     "Update a Load Balancer",
	NameSuggestions:      func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
	Fetch: func(s state.State, _ *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
		return s.Client().LoadBalancer().Get(s, idOrName)
	},
	DefineFlags: func(cmd *cobra.Command) {
		cmd.Flags().String("name", "", "Load Balancer name")
	},
	Update: func(s state.State, _ *cobra.Command, resource interface{}, flags map[string]pflag.Value) error {
		floatingIP := resource.(*hcloud.LoadBalancer)
		updOpts := hcloud.LoadBalancerUpdateOpts{
			Name: flags["name"].String(),
		}
		_, _, err := s.Client().LoadBalancer().Update(s, floatingIP, updOpts)
		if err != nil {
			return err
		}
		return nil
	},
}
View Source
var UpdateServiceCmd = base.Cmd{
	BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
		cmd := &cobra.Command{
			Use:                   "update-service [options] --listen-port <1-65535> <load-balancer>",
			Short:                 "Updates a service from a Load Balancer",
			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 to use for load balancing traffic")
		cmd.Flags().Bool("proxy-protocol", false, "Enable or disable (with --proxy-protocol=false) Proxy Protocol (true, false)")
		cmd.Flags().Bool("http-redirect-http", false, "Enable or disable redirect all traffic on port 80 to port 443 (true, false)")

		cmd.Flags().Bool("http-sticky-sessions", false, "Enable or disable (with --http-sticky-sessions=false) Sticky Sessions (true, false)")
		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().StringSlice("http-certificates", []string{}, "IDs or names of Certificates which should be 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 (true, false)")
		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, args []string) error {
		idOrName := args[0]
		listenPort, _ := cmd.Flags().GetInt("listen-port")

		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, 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 = &proxyProtocol
		}

		if cmd.Flag("http-redirect-http").Changed {
			redirectHTTP, _ := cmd.Flags().GetBool("http-redirect-http")
			opts.HTTP.RedirectHTTP = &redirectHTTP
		}
		if cmd.Flag("http-sticky-sessions").Changed {
			stickySessions, _ := cmd.Flags().GetBool("http-sticky-sessions")
			opts.HTTP.StickySessions = &stickySessions
		}
		if cmd.Flag("http-cookie-name").Changed {
			cookieName, _ := cmd.Flags().GetString("http-cookie-name")
			opts.HTTP.CookieName = &cookieName
		}
		if cmd.Flag("http-cookie-lifetime").Changed {
			cookieLifetime, _ := cmd.Flags().GetDuration("http-cookie-lifetime")
			opts.HTTP.CookieLifetime = &cookieLifetime
		}
		if cmd.Flag("http-certificates").Changed {
			certificates, _ := cmd.Flags().GetStringSlice("http-certificates")
			for _, idOrName := range certificates {
				cert, _, err := s.Client().Certificate().Get(s, idOrName)
				if err != nil {
					return err
				}
				opts.HTTP.Certificates = append(opts.HTTP.Certificates, cert)
			}
		}

		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 = &healthCheckPort
		}
		if cmd.Flag("health-check-interval").Changed {
			healthCheckInterval, _ := cmd.Flags().GetDuration("health-check-interval")
			opts.HealthCheck.Interval = &healthCheckInterval
		}
		if cmd.Flag("health-check-timeout").Changed {
			healthCheckTimeout, _ := cmd.Flags().GetDuration("health-check-timeout")
			opts.HealthCheck.Timeout = &healthCheckTimeout
		}
		if cmd.Flag("health-check-retries").Changed {
			healthCheckRetries, _ := cmd.Flags().GetInt("health-check-retries")
			opts.HealthCheck.Retries = &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 = &healthCheckHTTPDomain
			}
			if cmd.Flag("health-check-http-path").Changed {
				healthCheckHTTPPath, _ := cmd.Flags().GetString("health-check-http-path")
				opts.HealthCheck.HTTP.Path = &healthCheckHTTPPath
			}
			if cmd.Flag("health-check-http-response").Changed {
				healthCheckHTTPResponse, _ := cmd.Flags().GetString("health-check-http-response")
				opts.HealthCheck.HTTP.Response = &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 = &healthCheckHTTPTLS
			}
		}

		action, _, err := s.Client().LoadBalancer().UpdateService(s, loadBalancer, listenPort, opts)
		if err != nil {
			return err
		}
		if err := s.WaitForActions(s, cmd, action); err != nil {
			return err
		}
		cmd.Printf("Service %d on Load Balancer %d was updated\n", listenPort, loadBalancer.ID)

		return nil
	},
}

Functions

func Health added in v1.42.0

func Health(l *hcloud.LoadBalancer) string

func NewCommand

func NewCommand(s state.State) *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