loadbalancer

package
v1.49.0 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2024 License: MIT Imports: 21 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")

		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")

		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(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().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")
			}
		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 _, certificateID := range httpCertificates {
				opts.HTTP.Certificates = append(opts.HTTP.Certificates, &hcloud.Certificate{ID: certificateID})
			}
		}

		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")
		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)")

		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")

		opts := hcloud.LoadBalancerAttachToNetworkOpts{
			Network: network,
			IP:      ip,
		}
		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("LoadBalancer %d changed to type %s\n", loadBalancer.ID, loadBalancerType.Name)
		return nil
	},
}
View Source
var CreateCmd = base.CreateCmd{
	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"))

		return cmd
	},
	Run: func(s state.State, cmd *cobra.Command, _ []string) (any, 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")

		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}
		}
		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
		}
		loadBalancer, _, err := s.Client().LoadBalancer().GetByID(s, result.LoadBalancer.ID)
		if err != nil {
			return nil, nil, err
		}
		cmd.Printf("Load Balancer %d created\n", loadBalancer.ID)

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

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

	PrintResource: func(_ state.State, cmd *cobra.Command, resource any) {
		loadBalancer := resource.(*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{
	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(s state.State, _ *cobra.Command, idOrName string) (interface{}, interface{}, 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")
	},
	PrintText: func(s state.State, cmd *cobra.Command, resource interface{}) error {
		withLabelSelectorTargets, _ := cmd.Flags().GetBool("expand-targets")
		loadBalancer := resource.(*hcloud.LoadBalancer)
		cmd.Printf("ID:\t\t\t\t%d\n", loadBalancer.ID)
		cmd.Printf("Name:\t\t\t\t%s\n", loadBalancer.Name)
		cmd.Printf("Created:\t\t\t%s (%s)\n", util.Datetime(loadBalancer.Created), humanize.Time(loadBalancer.Created))
		cmd.Printf("Public Net:\n")
		cmd.Printf("  Enabled:\t\t\t%s\n", util.YesNo(loadBalancer.PublicNet.Enabled))
		cmd.Printf("  IPv4:\t\t\t\t%s\n", loadBalancer.PublicNet.IPv4.IP.String())
		cmd.Printf("  IPv4 DNS PTR:\t\t\t%s\n", loadBalancer.PublicNet.IPv4.DNSPtr)
		cmd.Printf("  IPv6:\t\t\t\t%s\n", loadBalancer.PublicNet.IPv6.IP.String())
		cmd.Printf("  IPv6 DNS PTR:\t\t\t%s\n", loadBalancer.PublicNet.IPv6.DNSPtr)

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

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

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

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

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

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

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

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

		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> <protection-level>...",
			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> <protection-level>...",
			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{
	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 },
	FetchLabels: func(s state.State, idOrName string) (map[string]string, int64, error) {
		loadBalancer, _, err := s.Client().LoadBalancer().Get(s, idOrName)
		if err != nil {
			return nil, 0, err
		}
		if loadBalancer == nil {
			return nil, 0, fmt.Errorf("load balancer not found: %s", idOrName)
		}
		return loadBalancer.Labels, loadBalancer.ID, nil
	},
	SetLabels: func(s state.State, id int64, labels map[string]string) error {
		opts := hcloud.LoadBalancerUpdateOpts{
			Labels: labels,
		}
		_, _, err := s.Client().LoadBalancer().Update(s, &hcloud.LoadBalancer{ID: id}, opts)
		return err
	},
}
View Source
var ListCmd = base.ListCmd{
	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) ([]interface{}, error) {
		opts := hcloud.LoadBalancerListOpts{ListOpts: listOpts}
		if len(sorts) > 0 {
			opts.Sort = sorts
		}
		loadBalancers, err := s.Client().LoadBalancer().AllWithOpts(s, opts)

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

	OutputTable: func(t *output.Table, _ hcapi2.Client) {
		t.
			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())
			})).
			AddFieldFn("health", output.FieldFn(func(obj interface{}) string {
				loadBalancer := obj.(*hcloud.LoadBalancer)
				return Health(loadBalancer)
			}))
	},

	Schema: func(resources []interface{}) interface{} {
		loadBalancerSchemas := make([]schema.LoadBalancer, 0, len(resources))
		for _, resource := range resources {
			loadBalancer := resource.(*hcloud.LoadBalancer)
			loadBalancerSchemas = append(loadBalancerSchemas, hcloud.SchemaFromLoadBalancer(loadBalancer))
		}
		return loadBalancerSchemas
	},
}
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("LoadBalancer 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", "", "LoadBalancer 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")
		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(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().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 = &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