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_dns.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ stackit dns [flags]
### SEE ALSO

* [stackit](./stackit.md) - Manage STACKIT resources using the command line
* [stackit dns lookup](./stackit_dns_lookup.md) - Looks up a domain on the STACKIT DNS resolvers
* [stackit dns record-set](./stackit_dns_record-set.md) - Provides functionality for DNS record set
* [stackit dns zone](./stackit_dns_zone.md) - Provides functionality for DNS zones

49 changes: 49 additions & 0 deletions docs/stackit_dns_lookup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## stackit dns lookup

Looks up a domain on the STACKIT DNS resolvers

### Synopsis

Looks up a domain on the STACKIT DNS resolvers.

```
stackit dns lookup DOMAIN [flags]
```

### Examples

```
Look up domain "www.example.com"
$ stackit dns lookup www.example.com

Look up the AAAA records of domain "www.example.com" on all STACKIT DNS resolvers
$ stackit dns lookup www.example.com --type AAAA --all-resolvers

Look up domain "www.example.com" including the raw DNS response in JSON format
$ stackit dns lookup www.example.com --include-raw-response --output-format json
```

### Options

```
--all-resolvers If set, all STACKIT DNS resolvers are queried instead of a single one
-h, --help Help for "stackit dns lookup"
--include-raw-response If set, the raw DNS response is included in the output. Only shown in JSON and YAML output
--type string Record type to look up. If not set, defaults to A (one of: [A, AAAA, SOA, CNAME, NS, MX, TXT, SRV, PTR, ALIAS, DNAME, CAA, DNSKEY, DS, LOC, NAPTR, SSHFP, TLSA, URI, CERT, SVCB, TYPE, CSYNC, HINFO, HTTPS, ANY])
```

### 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 dns](./stackit_dns.md) - Provides functionality for DNS

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.16.0
github.com/stackitcloud/stackit-sdk-go/services/automation v0.2.1
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.22.0
github.com/stackitcloud/stackit-sdk-go/services/dns v0.25.0
github.com/stackitcloud/stackit-sdk-go/services/dns v0.26.0
github.com/stackitcloud/stackit-sdk-go/services/edge v0.14.0
github.com/stackitcloud/stackit-sdk-go/services/git v0.16.0
github.com/stackitcloud/stackit-sdk-go/services/iaas v1.15.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,8 @@ github.com/stackitcloud/stackit-sdk-go/services/automation v0.2.1 h1:VxYQ4fCkuZA
github.com/stackitcloud/stackit-sdk-go/services/automation v0.2.1/go.mod h1:pDhpbmeDlthML6h4jyI7ZRGrG2C4Tx3aIGru5Ts6ISo=
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.22.0 h1:NyG5PvXB9+ldlKqbTfpp4YMb/Afg8LRDG5BIa+mBf+g=
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.22.0/go.mod h1:sr7UP8YdI18bH+2mfpy9qjsDqcPQU/+YduqH1Zw2JgY=
github.com/stackitcloud/stackit-sdk-go/services/dns v0.25.0 h1:Yn4etadrdEEPU8YcbvF7a/UExSqri+jUC62w62ic4N8=
github.com/stackitcloud/stackit-sdk-go/services/dns v0.25.0/go.mod h1:D0iv6XBYkaEwTjbBeom0VTZnwQMfwb48FC8R2jRg80c=
github.com/stackitcloud/stackit-sdk-go/services/dns v0.26.0 h1:WFOUn8EnbMvQC8tuEyB65sVLzA6mXsNTEWOVnQhOoYY=
github.com/stackitcloud/stackit-sdk-go/services/dns v0.26.0/go.mod h1:D0iv6XBYkaEwTjbBeom0VTZnwQMfwb48FC8R2jRg80c=
github.com/stackitcloud/stackit-sdk-go/services/edge v0.14.0 h1:TTwlI34FUb0AisiApxKs5brGNP3Ma9cTvdmbxzNxs40=
github.com/stackitcloud/stackit-sdk-go/services/edge v0.14.0/go.mod h1:FBBnDsQns6SjJYQrox3YSY7ydOa4T8FR3sXNwFRTsPc=
github.com/stackitcloud/stackit-sdk-go/services/git v0.16.0 h1:M75DCyPbTzTx4mPdIkBvOVE3/6Eda0rp8xLm40d02qc=
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/dns/dns.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dns

import (
"github.com/stackitcloud/stackit-cli/internal/cmd/dns/lookup"
recordset "github.com/stackitcloud/stackit-cli/internal/cmd/dns/record-set"
"github.com/stackitcloud/stackit-cli/internal/cmd/dns/zone"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
Expand All @@ -25,4 +26,5 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
func addSubcommands(cmd *cobra.Command, params *types.CmdParams) {
cmd.AddCommand(zone.NewCmd(params))
cmd.AddCommand(recordset.NewCmd(params))
cmd.AddCommand(lookup.NewCmd(params))
}
172 changes: 172 additions & 0 deletions internal/cmd/dns/lookup/lookup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package lookup

import (
"context"
"fmt"

"github.com/stackitcloud/stackit-cli/internal/pkg/types"

"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"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/dns/client"
"github.com/stackitcloud/stackit-cli/internal/pkg/tables"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"

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

const (
domainArg = "DOMAIN"

allResolversFlag = "all-resolvers"
includeRawResponseFlag = "include-raw-response"
)

var typeFlag = flags.StringEnumFlag(
"type",
dns.AllowedLookupDomainPayloadRecordTypeEnumValues,
"Record type to look up. If not set, defaults to A",
)

type inputModel struct {
*globalflags.GlobalFlagModel
Domain string
Type *dns.LookupDomainPayloadRecordType
AllResolvers bool
IncludeRawResponse bool
}

func NewCmd(params *types.CmdParams) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("lookup %s", domainArg),
Short: "Looks up a domain on the STACKIT DNS resolvers",
Long: "Looks up a domain on the STACKIT DNS resolvers.",
Args: args.SingleArg(domainArg, nil),
Example: examples.Build(
examples.NewExample(
`Look up domain "www.example.com"`,
"$ stackit dns lookup www.example.com"),
examples.NewExample(
`Look up the AAAA records of domain "www.example.com" on all STACKIT DNS resolvers`,
"$ stackit dns lookup www.example.com --type AAAA --all-resolvers"),
examples.NewExample(
`Look up domain "www.example.com" including the raw DNS response in JSON format`,
"$ stackit dns lookup www.example.com --include-raw-response --output-format json"),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(params.Printer, cmd, args)
if err != nil {
return err
}

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

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

return outputResult(params.Printer, model, resp)
},
}
configureFlags(cmd)
return cmd
}

func configureFlags(cmd *cobra.Command) {
typeFlag.Register(cmd.Flags())
cmd.Flags().Bool(allResolversFlag, false, "If set, all STACKIT DNS resolvers are queried instead of a single one")
cmd.Flags().Bool(includeRawResponseFlag, false, "If set, the raw DNS response is included in the output. Only shown in JSON and YAML output")
}

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

model := inputModel{
GlobalFlagModel: globalFlags,
Domain: domain,
Type: typeFlag.Ptr(),
AllResolvers: flags.FlagToBoolValue(p, cmd, allResolversFlag),
IncludeRawResponse: flags.FlagToBoolValue(p, cmd, includeRawResponseFlag),
}

if model.IncludeRawResponse && model.OutputFormat != print.JSONOutputFormat && model.OutputFormat != print.YAMLOutputFormat {
p.Warn("--%s is only shown in JSON or YAML output, set --output-format json or --output-format yaml to see the raw DNS response\n", includeRawResponseFlag)
}

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

func buildRequest(ctx context.Context, model *inputModel, apiClient *dns.APIClient) dns.ApiLookupDomainRequest {
payload := dns.LookupDomainPayload{
Address: utils.Ptr(model.Domain),
RecordType: model.Type,
}
if model.AllResolvers {
payload.Type = utils.Ptr(dns.LOOKUPDOMAINPAYLOADTYPE_ALL)
}
if model.IncludeRawResponse {
payload.IncludeRawResponse = utils.Ptr(true)
}
if model.Region != "" {
payload.Region = utils.Ptr(model.Region)
}

req := apiClient.DefaultAPI.LookupDomain(ctx)
req = req.LookupDomainPayload(payload)
return req
}

func outputResult(p *print.Printer, model *inputModel, resp *dns.LookupDomainResponse) error {
return p.OutputResult(model.OutputFormat, resp, func() error {
if resp == nil {
return fmt.Errorf("look up DNS domain response is empty")
}
table := tables.NewTable()
table.SetHeader("RESOLVER IP", "NAME", "TYPE", "TTL", "DATA")
rows := 0
for _, result := range resp.State {
// When querying all resolvers, also list the ones without records,
// so it's visible which resolvers answered
if model.AllResolvers && len(result.Records) == 0 {
table.AddRow(utils.PtrString(result.ResolverIP), "", "", "", "No records found")
rows++
continue
}
for _, record := range result.Records {
table.AddRow(
utils.PtrString(result.ResolverIP),
utils.PtrString(record.Name),
utils.PtrString(record.Type),
utils.PtrString(record.Ttl),
utils.PtrString(record.Data),
)
rows++
}
}
if rows == 0 {
p.Outputf("No records found for domain %q\n", model.Domain)
return nil
}

table.EnableAutoMergeOnColumns(1)
err := table.Display(p)
if err != nil {
return fmt.Errorf("render table: %w", err)
}
return nil
})
}
Loading
Loading