Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/stackit_beta.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ stackit beta [flags]

* [stackit](./stackit.md) - Manage STACKIT resources using the command line
* [stackit beta alb](./stackit_beta_alb.md) - Manages application loadbalancers
* [stackit beta cdn](./stackit_beta_cdn.md) - Manage CDN resources
* [stackit beta kms](./stackit_beta_kms.md) - Provides functionality for KMS
* [stackit beta sqlserverflex](./stackit_beta_sqlserverflex.md) - Provides functionality for SQLServer Flex

34 changes: 34 additions & 0 deletions docs/stackit_beta_cdn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## stackit beta cdn

Manage CDN resources

### Synopsis

Manage the lifecycle of CDN resources.

```
stackit beta cdn [flags]
```

### Options

```
-h, --help Help for "stackit beta cdn"
```

### 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" "yaml"]
-p, --project-id string Project ID
--region string Target region for region-specific requests
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
```

### SEE ALSO

* [stackit beta](./stackit_beta.md) - Contains beta STACKIT CLI commands
* [stackit beta cdn distribution](./stackit_beta_cdn_distribution.md) - Manage CDN distributions

34 changes: 34 additions & 0 deletions docs/stackit_beta_cdn_distribution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## stackit beta cdn distribution

Manage CDN distributions

### Synopsis

Manage the lifecycle of CDN distributions.

```
stackit beta cdn distribution [flags]
```

### Options

```
-h, --help Help for "stackit beta cdn distribution"
```

### 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" "yaml"]
-p, --project-id string Project ID
--region string Target region for region-specific requests
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
```

### SEE ALSO

* [stackit beta cdn](./stackit_beta_cdn.md) - Manage CDN resources
* [stackit beta cdn distribution list](./stackit_beta_cdn_distribution_list.md) - List CDN distributions

44 changes: 44 additions & 0 deletions docs/stackit_beta_cdn_distribution_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## stackit beta cdn distribution list

List CDN distributions

### Synopsis

List all CDN distributions in your account.

```
stackit beta cdn distribution list [flags]
```

### Examples

```
List all CDN distributions
$ stackit beta cdn distribution list

List all CDN distributions sorted by id
$ stackit beta cdn distribution list --sort-by=id
```

### Options

```
-h, --help Help for "stackit beta cdn distribution list"
--sort-by string Sort entries by a specific field, one of ["id" "createdAt" "updatedAt" "originUrl" "status" "originUrlRelated"] (default "createdAt")
```

### 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" "yaml"]
-p, --project-id string Project ID
--region string Target region for region-specific requests
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
```

### SEE ALSO

* [stackit beta cdn distribution](./stackit_beta_cdn_distribution.md) - Manage CDN distributions

1 change: 1 addition & 0 deletions docs/stackit_config_set.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ stackit config set [flags]
```
--allowed-url-domain string Domain name, used for the verification of the URLs that are given in the custom identity provider endpoint and "STACKIT curl" command
--authorization-custom-endpoint string Authorization API base URL, used in calls to this API
--cdn-custom-endpoint string CDN API base URL, used in calls to this API
--dns-custom-endpoint string DNS API base URL, used in calls to this API
-h, --help Help for "stackit config set"
--iaas-custom-endpoint string IaaS API base URL, used in calls to this API
Expand Down
1 change: 1 addition & 0 deletions docs/stackit_config_unset.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ stackit config unset [flags]
--allowed-url-domain Domain name, used for the verification of the URLs that are given in the IDP endpoint and curl commands. If unset, defaults to stackit.cloud
--async Configuration option to run commands asynchronously
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
--cdn-custom-endpoint Custom CDN endpoint URL. If unset, uses the default base URL
--dns-custom-endpoint DNS API base URL. If unset, uses the default base URL
-h, --help Help for "stackit config unset"
--iaas-custom-endpoint IaaS API base URL. If unset, uses the default base URL
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/stackitcloud/stackit-sdk-go/core v0.19.0
github.com/stackitcloud/stackit-sdk-go/services/alb v0.7.1
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.9.0
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.6.0
github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1
github.com/stackitcloud/stackit-sdk-go/services/git v0.9.0
github.com/stackitcloud/stackit-sdk-go/services/iaas v1.2.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,8 @@ github.com/stackitcloud/stackit-sdk-go/services/alb v0.7.1 h1:DaJkEN/6l+AJEQ3Dr+
github.com/stackitcloud/stackit-sdk-go/services/alb v0.7.1/go.mod h1:SzA+UsSNv4D9IvNT7hwYPewgAvUgj5WXIU2tZ0XaMBI=
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.9.0 h1:7ZKd3b+E/R4TEVShLTXxx5FrsuDuJBOyuVOuKTMa4mo=
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.9.0/go.mod h1:/FoXa6hF77Gv8brrvLBCKa5ie1Xy9xn39yfHwaln9Tw=
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.6.0 h1:Q+qIdejeMsYMkbtVoI9BpGlKGdSVFRBhH/zj44SP8TM=
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.6.0/go.mod h1:YGadfhuy8yoseczTxF7vN4t9ES2WxGQr0Pug14ii7y4=
github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1 h1:CnhAMLql0MNmAeq4roQKN8OpSKX4FSgTU6Eu6detB4I=
github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1/go.mod h1:7Bx85knfNSBxulPdJUFuBePXNee3cO+sOTYnUG6M+iQ=
github.com/stackitcloud/stackit-sdk-go/services/git v0.9.0 h1:zuoJnsLnjxdQcQbs7gUXYzrN0Ip5NXj+6LFBp1EO6cg=
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/beta/beta.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb"
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/cdn"
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/kms"
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/sqlserverflex"
"github.com/stackitcloud/stackit-cli/internal/cmd/params"
Expand Down Expand Up @@ -40,4 +41,5 @@ func addSubcommands(cmd *cobra.Command, params *params.CmdParams) {
cmd.AddCommand(sqlserverflex.NewCmd(params))
cmd.AddCommand(alb.NewCmd(params))
cmd.AddCommand(kms.NewCmd(params))
cmd.AddCommand(cdn.NewCmd(params))
}
25 changes: 25 additions & 0 deletions internal/cmd/beta/cdn/cdn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cdn

import (
"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/cdn/distribution"
"github.com/stackitcloud/stackit-cli/internal/cmd/params"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
)

func NewCmd(params *params.CmdParams) *cobra.Command {
cmd := &cobra.Command{
Use: "cdn",
Short: "Manage CDN resources",
Long: "Manage the lifecycle of CDN resources.",
Args: args.NoArgs,
Run: utils.CmdHelp,
}
addSubcommands(cmd, params)
return cmd
}

func addSubcommands(cmd *cobra.Command, params *params.CmdParams) {
cmd.AddCommand(distribution.NewCommand(params))
}
24 changes: 24 additions & 0 deletions internal/cmd/beta/cdn/distribution/distribution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package distribution

import (
"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/cdn/distribution/list"
"github.com/stackitcloud/stackit-cli/internal/cmd/params"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
)

func NewCommand(params *params.CmdParams) *cobra.Command {
cmd := &cobra.Command{
Use: "distribution",
Short: "Manage CDN distributions",
Long: "Manage the lifecycle of CDN distributions.",
Args: cobra.NoArgs,
Run: utils.CmdHelp,
}
addSubcommands(cmd, params)
return cmd
}

func addSubcommands(cmd *cobra.Command, params *params.CmdParams) {
cmd.AddCommand(list.NewCmd(params))
}
153 changes: 153 additions & 0 deletions internal/cmd/beta/cdn/distribution/list/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package list

import (
"context"
"fmt"
"strings"

"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-cli/internal/cmd/params"
"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/flags"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/cdn/client"
"github.com/stackitcloud/stackit-cli/internal/pkg/tables"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
sdkUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/cdn"
)

type inputModel struct {
*globalflags.GlobalFlagModel
SortBy string
}

const (
sortByFlag = "sort-by"
)

func NewCmd(params *params.CmdParams) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List CDN distributions",
Long: "List all CDN distributions in your account.",
Args: args.NoArgs,
Example: examples.Build(
examples.NewExample(
`List all CDN distributions`,
`$ stackit beta cdn distribution list`,
),
examples.NewExample(
`List all CDN distributions sorted by id`,
`$ stackit beta cdn distribution list --sort-by=id`,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background() // should this be cancellable?

model, err := parseInput(params.Printer, cmd, args)
if err != nil {
return err
}

apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion)
if err != nil {
return err
}

distributions, err := fetchDistributions(ctx, model, apiClient)
if err != nil {
return fmt.Errorf("fetch distributions: %w", err)
}

return outputResult(params.Printer, model.OutputFormat, distributions)
},
}

configureFlags(cmd)
return cmd
}

var sortByFlagOptions = []string{"id", "createdAt", "updatedAt", "originUrl", "status", "originUrlRelated"}

func configureFlags(cmd *cobra.Command) {
// same default as apiClient
cmd.Flags().Var(flags.EnumFlag(false, "createdAt", sortByFlagOptions...), sortByFlag, fmt.Sprintf("Sort entries by a specific field, one of %q", sortByFlagOptions))
}

func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) {
globalFlags := globalflags.Parse(p, cmd)
if globalFlags.ProjectId == "" {
return nil, &errors.ProjectIdError{}
}

model := inputModel{
GlobalFlagModel: globalFlags,
SortBy: flags.FlagWithDefaultToStringValue(p, cmd, sortByFlag),
}

p.DebugInputModel(model)
return &model, nil
}

func buildRequest(ctx context.Context, model *inputModel, apiClient *cdn.APIClient, nextPageID cdn.ListDistributionsResponseGetNextPageIdentifierAttributeType) cdn.ApiListDistributionsRequest {
req := apiClient.ListDistributions(ctx, model.GlobalFlagModel.ProjectId)
req = req.SortBy(model.SortBy)
req = req.PageSize(100)
if nextPageID != nil {
req = req.PageIdentifier(*nextPageID)
}
return req
}

func outputResult(p *print.Printer, outputFormat string, distributions []cdn.Distribution) error {
if distributions == nil {
distributions = make([]cdn.Distribution, 0) // otherwise prints null in json output
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good catch indeed! Any chance we can solve this in a central place for all commands?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea, I'll investigate this a bit, don't know much about go reflection yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With reflection I'd add this in Printer.OutputResult():

	val := reflect.ValueOf(output)
	if val.IsNil() {
		// when passing a nil slice or map, JSON and YAML marshal to "null"
		// so we need to create an empty slice or map to have "[]" or "{}" output instead
		switch val.Kind() {
		case reflect.Slice:
			output = make([]any, 0)
		case reflect.Map:
			output = make(map[any]any)
		default:
			// do nothing
		}
	}

The linked document suggests type switches, which would not work here.

Another solution without reflection, that comes to mind, would be to introduce specialized OutputResult functions, like OutputResultSlice/Map.

}
return p.OutputResult(outputFormat, distributions, func() error {
if len(distributions) == 0 {
p.Outputln("No CDN distributions found")
return nil
}

table := tables.NewTable()
table.SetHeader("ID", "REGIONS", "STATUS")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rubenhoenle, when using the table output we only get these columns. When using the JSON format we would get all fields of cdn.Distribution. Should I introduce here custom struct that only contains ID, REGIONS and STATUS in JSON?

for i := range distributions {
d := &distributions[i]
joinedRegions := strings.Join(sdkUtils.EnumSliceToStringSlice(*d.Config.Regions), ", ")
table.AddRow(
utils.PtrString(d.Id),
joinedRegions,
utils.PtrString(d.Status),
)
}
err := table.Display(p)
if err != nil {
return fmt.Errorf("render table: %w", err)
}
return nil
})
}

func fetchDistributions(ctx context.Context, model *inputModel, apiClient *cdn.APIClient) ([]cdn.Distribution, error) {
var nextPageID cdn.ListDistributionsResponseGetNextPageIdentifierAttributeType
var distributions []cdn.Distribution
for {
request := buildRequest(ctx, model, apiClient, nextPageID)
response, err := request.Execute()
if err != nil {
return nil, fmt.Errorf("list distributions: %w", err)
}
nextPageID = response.NextPageIdentifier
if response.Distributions != nil {
distributions = append(distributions, *response.Distributions...)
}
if nextPageID == nil {
break
}
}
return distributions, nil
}
Loading
Loading