Skip to content

Commit

Permalink
Feat: DNS secondary zones and zone files (#458)
Browse files Browse the repository at this point in the history
* implement dns secondary zones functionalities

* refactor to avoid cyclic imports

* add completer pkg and zone files implementation

* enable silence usage

* add bats tests

* make fmt

* make docs

* add secondary zone records list

* update changelog
  • Loading branch information
glimberea authored Oct 14, 2024
1 parent 67b67fd commit 7167cd1
Show file tree
Hide file tree
Showing 52 changed files with 1,831 additions and 210 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Added
- Added support for `manpages` generation via `ionosctl man` command
- Added support for DNS `secondary-zones` and `zone files`

### Changed
- Added authentication warning to `image upload` help text
Expand Down
71 changes: 71 additions & 0 deletions commands/dns/completer/completer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package completer

import (
"context"

"github.com/ionos-cloud/ionosctl/v6/internal/client"
"github.com/ionos-cloud/ionosctl/v6/internal/completions"
"github.com/ionos-cloud/ionosctl/v6/internal/config"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/jsonpaths"
"github.com/ionos-cloud/ionosctl/v6/pkg/functional"

"github.com/ionos-cloud/sdk-go-dns"
"github.com/spf13/viper"
)

func SecondaryZonesIDs() []string {
// Hack to enforce the dns-level flag default for API URL on the completions too
if url := config.GetServerUrl(); url == constants.DefaultApiURL {
viper.Set(constants.ArgServerUrl, "")
}

secondaryZones, _, err := client.Must().DnsClient.SecondaryZonesApi.SecondaryzonesGet(context.Background()).Execute()
if err != nil {
return nil
}

secondaryZonesConverted, err := json2table.ConvertJSONToTable("items", jsonpaths.DnsSecondaryZone, secondaryZones)
if err != nil {
return nil
}

return completions.NewCompleter(
secondaryZonesConverted, "Id",
).AddInfo("Name").AddInfo("State", "(%v)").ToString()
}

// Zones returns all zones matching the given filters
func Zones(fs ...Filter) (ionoscloud.ZoneReadList, error) {
// Hack to enforce the dns-level flag default for API URL on the completions too
if url := config.GetServerUrl(); url == constants.DefaultApiURL {
viper.Set(constants.ArgServerUrl, "")
}

req := client.Must().DnsClient.ZonesApi.ZonesGet(context.Background())

for _, f := range fs {
var err error
req, err = f(req)
if err != nil {
return ionoscloud.ZoneReadList{}, err
}
}

ls, _, err := req.Execute()
if err != nil {
return ionoscloud.ZoneReadList{}, err
}
return ls, nil
}

func ZonesProperty[V any](f func(ionoscloud.ZoneRead) V, fs ...Filter) []V {
recs, err := Zones(fs...)
if err != nil {
return nil
}
return functional.Map(*recs.Items, f)
}

type Filter func(request ionoscloud.ApiZonesGetRequest) (ionoscloud.ApiZonesGetRequest, error)
2 changes: 2 additions & 0 deletions commands/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/ionos-cloud/ionosctl/v6/commands/dns/quota"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/record"
reverse_record "github.com/ionos-cloud/ionosctl/v6/commands/dns/reverse-record"
secondary_zones "github.com/ionos-cloud/ionosctl/v6/commands/dns/secondary-zones"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"
"github.com/ionos-cloud/ionosctl/v6/internal/core"
"github.com/spf13/cobra"
Expand All @@ -23,6 +24,7 @@ func DNSCommand() *core.Command {
cmd.AddCommand(reverse_record.Root())
cmd.AddCommand(quota.Root())
cmd.AddCommand(dnssec.Root())
cmd.AddCommand(secondary_zones.Root())

return cmd
}
9 changes: 5 additions & 4 deletions commands/dns/dns_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/record"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/pkg/functional"
dns "github.com/ionos-cloud/sdk-go-dns"
Expand Down Expand Up @@ -107,9 +108,9 @@ func TestZone(t *testing.T) {
assert.NotEmpty(t, sharedZ.Properties)
assert.Equal(t, randDesc, *sharedZ.Properties.Description)

resolvedId, err := zone.Resolve(randName)
resolvedId, err := utils.ZoneResolve(randName)
assert.NoError(t, err)
assert.Equal(t, *sharedZ.Id, resolvedId) // I added these 3 lines later - to test zone.Resolve too
assert.Equal(t, *sharedZ.Id, resolvedId) // I added these 3 lines later - to test zone.ZoneResolve too

// === `ionosctl dns z get`
c = zone.ZonesFindByIdCmd()
Expand Down Expand Up @@ -140,7 +141,7 @@ func TestZone(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, randDesc, *zoneThroughSdk.Properties.Description)

resolvedId, err = zone.Resolve(randName)
resolvedId, err = utils.ZoneResolve(randName)
assert.NoError(t, err)
assert.Equal(t, *sharedZ.Id, resolvedId)
}
Expand Down Expand Up @@ -175,7 +176,7 @@ func TestRecord(t *testing.T) {
assert.NotEmpty(t, r.Properties)
assert.Equal(t, randIp, *r.Properties.Content)

// also test record.Resolve
// also test record.ZoneResolve
resolvedId, err := record.Resolve(randName)
assert.NoError(t, err)
assert.Equal(t, *r.Id, resolvedId)
Expand Down
7 changes: 4 additions & 3 deletions commands/dns/dnssec/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"context"
"fmt"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/completer"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/client"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/core"
Expand Down Expand Up @@ -43,7 +44,7 @@ func Create() *core.Command {
return nil
},
CmdRun: func(c *core.CommandConfig) error {
zoneId, err := zone.Resolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
zoneId, err := utils.ZoneResolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
if err != nil {
return err
}
Expand Down Expand Up @@ -84,7 +85,7 @@ func Create() *core.Command {

cmd.AddStringFlag(constants.FlagZone, constants.FlagZoneShort, "", constants.DescZone)
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagZone, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return zone.ZonesProperty(func(t dns.ZoneRead) string {
return completer.ZonesProperty(func(t dns.ZoneRead) string {
return *t.Properties.ZoneName
}), cobra.ShellCompDirectiveNoFileComp
})
Expand Down
7 changes: 4 additions & 3 deletions commands/dns/dnssec/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"context"
"fmt"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/completer"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/client"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/core"
Expand All @@ -30,7 +31,7 @@ func Delete() *core.Command {
},
CmdRun: func(c *core.CommandConfig) error {
zoneName := viper.GetString(core.GetFlagName(c.NS, constants.FlagZone))
zoneId, err := zone.Resolve(zoneName)
zoneId, err := utils.ZoneResolve(zoneName)
if err != nil {
return err
}
Expand All @@ -48,7 +49,7 @@ func Delete() *core.Command {

cmd.AddStringFlag(constants.FlagZone, constants.FlagZoneShort, "", constants.DescZone)
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagZone, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return zone.ZonesProperty(func(t dns.ZoneRead) string {
return completer.ZonesProperty(func(t dns.ZoneRead) string {
return *t.Properties.ZoneName
}), cobra.ShellCompDirectiveNoFileComp
})
Expand Down
7 changes: 4 additions & 3 deletions commands/dns/dnssec/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"context"
"fmt"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/completer"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/client"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/core"
Expand Down Expand Up @@ -34,7 +35,7 @@ ionosctl dns keys list --zone ZONE --cols PubKey --no-headers`,
return nil
},
CmdRun: func(c *core.CommandConfig) error {
zoneId, err := zone.Resolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
zoneId, err := utils.ZoneResolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
if err != nil {
return err
}
Expand Down Expand Up @@ -63,7 +64,7 @@ ionosctl dns keys list --zone ZONE --cols PubKey --no-headers`,

cmd.AddStringFlag(constants.FlagZone, constants.FlagZoneShort, "", constants.DescZone)
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagZone, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return zone.ZonesProperty(func(t dns.ZoneRead) string {
return completer.ZonesProperty(func(t dns.ZoneRead) string {
return *t.Properties.ZoneName
}), cobra.ShellCompDirectiveNoFileComp
})
Expand Down
8 changes: 4 additions & 4 deletions commands/dns/record/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import (
"context"
"fmt"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/completer"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/jsonpaths"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/jsontabwriter"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/tabheaders"
"github.com/ionos-cloud/ionosctl/v6/pkg/pointer"
"github.com/ionos-cloud/ionosctl/v6/pkg/uuidgen"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"

dns "github.com/ionos-cloud/sdk-go-dns"

"github.com/ionos-cloud/ionosctl/v6/internal/client"
Expand Down Expand Up @@ -41,7 +41,7 @@ func ZonesRecordsPostCmd() *core.Command {
input := dns.Record{}
modifyRecordPropertiesFromFlags(c, &input)

zoneId, err := zone.Resolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
zoneId, err := utils.ZoneResolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
if err != nil {
return err
}
Expand Down Expand Up @@ -73,7 +73,7 @@ func ZonesRecordsPostCmd() *core.Command {

cmd.AddStringFlag(constants.FlagZone, constants.FlagZoneShort, "", "The ID or name of the DNS zone", core.RequiredFlagOption())
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagZone, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return zone.ZonesProperty(func(t dns.ZoneRead) string {
return completer.ZonesProperty(func(t dns.ZoneRead) string {
return *t.Properties.ZoneName
}), cobra.ShellCompDirectiveNoFileComp
})
Expand Down
7 changes: 4 additions & 3 deletions commands/dns/record/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"strings"

"github.com/gofrs/uuid/v5"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/completer"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/pkg/confirm"
"github.com/ionos-cloud/ionosctl/v6/pkg/functional"
Expand Down Expand Up @@ -55,7 +56,7 @@ ionosctl dns r delete --record PARTIAL_NAME --zone ZONE`,
return deleteAll(c)
}

zoneId, err := zone.Resolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
zoneId, err := utils.ZoneResolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
if err != nil {
return err
}
Expand Down Expand Up @@ -97,7 +98,7 @@ ionosctl dns r delete --record PARTIAL_NAME --zone ZONE`,
cmd.AddBoolFlag(constants.ArgAll, constants.ArgAllShort, false, fmt.Sprintf("Delete all records. You can optionally filter the deleted records using --%s (full name / ID) and --%s (partial name)", constants.FlagZone, constants.FlagRecord))
cmd.AddStringFlag(constants.FlagZone, constants.FlagZoneShort, "", fmt.Sprintf("The full name or ID of the zone of the containing the target record. If --%s is set this is applied as a filter - limiting to records within this zone", constants.ArgAll))
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagZone, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return zone.ZonesProperty(func(t dns.ZoneRead) string {
return completer.ZonesProperty(func(t dns.ZoneRead) string {
return *t.Properties.ZoneName
}), cobra.ShellCompDirectiveNoFileComp
})
Expand Down
10 changes: 4 additions & 6 deletions commands/dns/record/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"context"
"fmt"

"github.com/ionos-cloud/ionosctl/v6/commands/dns/zone"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/completer"
"github.com/ionos-cloud/ionosctl/v6/commands/dns/utils"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/jsonpaths"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/jsontabwriter"
Expand Down Expand Up @@ -33,7 +34,7 @@ func ZonesRecordsFindByIdCmd() *core.Command {
return nil
},
CmdRun: func(c *core.CommandConfig) error {
zoneId, err := zone.Resolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
zoneId, err := utils.ZoneResolve(viper.GetString(core.GetFlagName(c.NS, constants.FlagZone)))
if err != nil {
return err
}
Expand All @@ -51,9 +52,6 @@ func ZonesRecordsFindByIdCmd() *core.Command {
}

cols, _ := c.Command.Command.Flags().GetStringSlice(constants.ArgCols)
// if err != nil {
// return err
// }

out, err := jsontabwriter.GenerateOutput("", jsonpaths.DnsRecord, r,
tabheaders.GetHeadersAllDefault(defaultCols, cols))
Expand All @@ -69,7 +67,7 @@ func ZonesRecordsFindByIdCmd() *core.Command {

cmd.AddStringFlag(constants.FlagZone, constants.FlagZoneShort, "", constants.DescZone)
_ = cmd.Command.RegisterFlagCompletionFunc(constants.FlagZone, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return zone.ZonesProperty(func(t dns.ZoneRead) string {
return completer.ZonesProperty(func(t dns.ZoneRead) string {
return *t.Properties.ZoneName
}), cobra.ShellCompDirectiveNoFileComp
})
Expand Down
Loading

0 comments on commit 7167cd1

Please sign in to comment.