Skip to content
Merged
3 changes: 3 additions & 0 deletions docs/stackit_load-balancer.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ stackit load-balancer [flags]
### SEE ALSO

* [stackit](./stackit.md) - Manage STACKIT resources using the command line
* [stackit load-balancer describe](./stackit_load-balancer_describe.md) - Shows details of a Load Balancer
* [stackit load-balancer generate-payload](./stackit_load-balancer_generate-payload.md) - Generates a payload to create/update a Load Balancer
* [stackit load-balancer list](./stackit_load-balancer_list.md) - Lists all Load Balancers
* [stackit load-balancer quota](./stackit_load-balancer_quota.md) - Shows the configured Load Balancer quota

42 changes: 42 additions & 0 deletions docs/stackit_load-balancer_describe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## stackit load-balancer describe

Shows details of a Load Balancer

### Synopsis

Shows details of a Load Balancer.

```
stackit load-balancer describe LOAD_BALANCER_NAME [flags]
```

### Examples

```
Get details of a load balancer with name "my-load-balancer"
$ stackit load-balancer describe my-load-balancer

Get details of a load-balancer with name "my-load-balancer" in a table format
$ stackit load-balancer describe my-load-balancer --output-format pretty
```

### Options

```
-h, --help Help for "stackit load-balancer describe"
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty" "none"]
-p, --project-id string Project ID
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
```

### SEE ALSO

* [stackit load-balancer](./stackit_load-balancer.md) - Provides functionality for Load Balancer

46 changes: 46 additions & 0 deletions docs/stackit_load-balancer_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## stackit load-balancer list

Lists all Load Balancers

### Synopsis

Lists all Load Balancers.

```
stackit load-balancer list [flags]
```

### Examples

```
List all load balancers
$ stackit load-balancer list

List all loadbalancers in JSON format
$ stackit load-balancer list --output-format json

List up to 10 load balancers
$ stackit load-balancer list --limit 10
```

### Options

```
-h, --help Help for "stackit load-balancer list"
--limit int Maximum number of entries to list
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty" "none"]
-p, --project-id string Project ID
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
```

### SEE ALSO

* [stackit load-balancer](./stackit_load-balancer.md) - Provides functionality for Load Balancer

39 changes: 39 additions & 0 deletions docs/stackit_load-balancer_quota.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## stackit load-balancer quota

Shows the configured Load Balancer quota

### Synopsis

Shows the configured Load Balancer quota for the project. If you want to change the quota, please create a support ticket in the STACKIT Help Center (https://support.stackit.cloud)

```
stackit load-balancer quota [flags]
```

### Examples

```
Get the configured load balancer quota for the project
$ stackit load-balancer quota
```

### Options

```
-h, --help Help for "stackit load-balancer quota"
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty" "none"]
-p, --project-id string Project ID
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
```

### SEE ALSO

* [stackit load-balancer](./stackit_load-balancer.md) - Provides functionality for Load Balancer

188 changes: 188 additions & 0 deletions internal/cmd/load-balancer/describe/describe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package describe

import (
"context"
"encoding/json"
"fmt"
"strings"

"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/load-balancer/client"
"github.com/stackitcloud/stackit-cli/internal/pkg/tables"

"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-sdk-go/services/loadbalancer"
)

const (
loadBalancerNameArg = "LOAD_BALANCER_NAME"
)

type inputModel struct {
*globalflags.GlobalFlagModel
LoadBalancerName string
}

func NewCmd(p *print.Printer) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("describe %s", loadBalancerNameArg),
Short: "Shows details of a Load Balancer",
Long: "Shows details of a Load Balancer.",
Args: args.SingleArg(loadBalancerNameArg, nil),
Example: examples.Build(
examples.NewExample(
`Get details of a load balancer with name "my-load-balancer"`,
"$ stackit load-balancer describe my-load-balancer"),
examples.NewExample(
`Get details of a load-balancer with name "my-load-balancer" in a table format`,
"$ stackit load-balancer describe my-load-balancer --output-format pretty"),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(p, cmd, args)
if err != nil {
return err
}
// Configure API client
apiClient, err := client.ConfigureClient(p)
if err != nil {
return err
}

// Call API
req := buildRequest(ctx, model, apiClient)
resp, err := req.Execute()
if err != nil {
return fmt.Errorf("read load balancer: %w", err)
}

return outputResult(p, model.OutputFormat, resp)
},
}
return cmd
}

func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
loadBalancerName := inputArgs[0]

globalFlags := globalflags.Parse(p, cmd)
if globalFlags.ProjectId == "" {
return nil, &errors.ProjectIdError{}
}

return &inputModel{
GlobalFlagModel: globalFlags,
LoadBalancerName: loadBalancerName,
}, nil
}

func buildRequest(ctx context.Context, model *inputModel, apiClient *loadbalancer.APIClient) loadbalancer.ApiGetLoadBalancerRequest {
req := apiClient.GetLoadBalancer(ctx, model.ProjectId, model.LoadBalancerName)
return req
}

func outputResult(p *print.Printer, outputFormat string, loadBalancer *loadbalancer.LoadBalancer) error {
switch outputFormat {
case print.PrettyOutputFormat:
return outputResultAsTable(p, loadBalancer)
default:
details, err := json.MarshalIndent(loadBalancer, "", " ")
if err != nil {
return fmt.Errorf("marshal load balancer: %w", err)
}
p.Outputln(string(details))

return nil
}
}

func outputResultAsTable(p *print.Printer, loadBalancer *loadbalancer.LoadBalancer) error {
content := renderLoadBalancer(loadBalancer)

if loadBalancer.Listeners != nil {
content += renderListeners(*loadBalancer.Listeners)
}

if loadBalancer.TargetPools != nil {
content += renderTargetPools(*loadBalancer.TargetPools)
}

err := p.PagerDisplay(content)
if err != nil {
return fmt.Errorf("display output: %w", err)
}

return nil
}

func renderLoadBalancer(loadBalancer *loadbalancer.LoadBalancer) string {
acl := []string{}
privateAccessOnly := false
if loadBalancer.Options != nil {
if loadBalancer.Options.AccessControl != nil && loadBalancer.Options.AccessControl.AllowedSourceRanges != nil {
acl = *loadBalancer.Options.AccessControl.AllowedSourceRanges
}

if loadBalancer.Options.PrivateNetworkOnly != nil {
privateAccessOnly = *loadBalancer.Options.PrivateNetworkOnly
}
}

var networkId string
if loadBalancer.Networks != nil && len(*loadBalancer.Networks) > 0 {
networks := *loadBalancer.Networks
networkId = *networks[0].NetworkId
}

table := tables.NewTable()
table.AddRow("NAME", *loadBalancer.Name)
table.AddSeparator()
table.AddRow("STATE", *loadBalancer.Status)
table.AddSeparator()
table.AddRow("PRIVATE ACCESS ONLY", privateAccessOnly)
table.AddSeparator()
table.AddRow("ATTACHED PUBLIC IP", *loadBalancer.ExternalAddress)
table.AddSeparator()
table.AddRow("ATTACHED NETWORK ID", networkId)
table.AddSeparator()
table.AddRow("ACL", acl)
return table.Render()
}

func renderListeners(listeners []loadbalancer.Listener) string {
table := tables.NewTable()
table.SetHeader("LISTENER NAME", "PORT", "PROTOCOL", "TARGET POOL")
for i := range listeners {
listener := listeners[i]
table.AddRow(*listener.Name, *listener.Port, *listener.Protocol, *listener.TargetPool)
}

return table.Render()
}

func renderTargetPools(targetPools []loadbalancer.TargetPool) string {
table := tables.NewTable()
table.SetHeader("TARGET POOL NAME", "PORT", "TARGETS", "SESSION PERSISTENCE", "HEALTH CHECK INTERVAL (S)", "DOWN AFTER (CHECKS)", "UP AFTER (CHECKS)")
for _, targetPool := range targetPools {
var targetsArray []string
for _, t := range *targetPool.Targets {
targetsArray = append(targetsArray, fmt.Sprintf("%s (%s)", *t.DisplayName, *t.Ip))
}
targets := strings.Join(targetsArray, "\n")

sessionPersistence := "None"
if targetPool.SessionPersistence != nil && targetPool.SessionPersistence.UseSourceIpAddress != nil && *targetPool.SessionPersistence.UseSourceIpAddress {
sessionPersistence = "Use Source IP"
}

healthCheck := targetPool.ActiveHealthCheck

table.AddRow(*targetPool.Name, *targetPool.TargetPort, targets, sessionPersistence, *healthCheck.Interval, *healthCheck.UnhealthyThreshold, *healthCheck.HealthyThreshold)
}

return table.Render()
}
Loading