forked from coop-cloud/abra
refactor!: abra domain -> abra record + prompts
This reconciles the fact that we manage records and not domains which was a bad first naming take on this imho. Now it is clear that we are manipulating domain name records and not entire zones. The UX of record creation/deletion now mirrors the UX of new apps. All the things are prompted for.
This commit is contained in:
parent
9f9248b987
commit
5ae06bbd42
|
@ -8,9 +8,9 @@ import (
|
|||
|
||||
"coopcloud.tech/abra/cli/app"
|
||||
"coopcloud.tech/abra/cli/catalogue"
|
||||
"coopcloud.tech/abra/cli/domain"
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/cli/recipe"
|
||||
"coopcloud.tech/abra/cli/record"
|
||||
"coopcloud.tech/abra/cli/server"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
logrusStack "github.com/Gurpartap/logrus-stack"
|
||||
|
@ -60,7 +60,7 @@ func newAbraApp(version, commit string) *cli.App {
|
|||
server.ServerCommand,
|
||||
recipe.RecipeCommand,
|
||||
catalogue.CatalogueCommand,
|
||||
domain.DomainCommand,
|
||||
record.RecordCommand,
|
||||
UpgradeCommand,
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
|
|
|
@ -72,11 +72,9 @@ var DNSProviderFlag = &cli.StringFlag{
|
|||
Aliases: []string{"p"},
|
||||
Usage: "DNS provider",
|
||||
Destination: &DNSProvider,
|
||||
Required: true,
|
||||
}
|
||||
|
||||
var NoInput bool
|
||||
|
||||
var NoInputFlag = &cli.BoolFlag{
|
||||
Name: "no-input",
|
||||
Value: false,
|
||||
|
@ -84,3 +82,53 @@ var NoInputFlag = &cli.BoolFlag{
|
|||
Usage: "Toggle non-interactive mode",
|
||||
Destination: &NoInput,
|
||||
}
|
||||
|
||||
var DNSType string
|
||||
|
||||
var DNSTypeFlag = &cli.StringFlag{
|
||||
Name: "type",
|
||||
Value: "",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Domain name record type (e.g. A)",
|
||||
Destination: &DNSType,
|
||||
}
|
||||
|
||||
var DNSName string
|
||||
|
||||
var DNSNameFlag = &cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Domain name record name (e.g. mysubdomain)",
|
||||
Destination: &DNSName,
|
||||
}
|
||||
|
||||
var DNSValue string
|
||||
|
||||
var DNSValueFlag = &cli.StringFlag{
|
||||
Name: "value",
|
||||
Value: "",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "Domain name record value (e.g. 192.168.1.1)",
|
||||
Destination: &DNSValue,
|
||||
}
|
||||
|
||||
var DNSTTL int
|
||||
|
||||
var DNSTTLFlag = &cli.IntFlag{
|
||||
Name: "ttl",
|
||||
Value: 86400,
|
||||
Aliases: []string{"T"},
|
||||
Usage: "Domain name TTL value (e.g. 86400)",
|
||||
Destination: &DNSTTL,
|
||||
}
|
||||
|
||||
var DNSPriority int
|
||||
|
||||
var DNSPriorityFlag = &cli.IntFlag{
|
||||
Name: "priority",
|
||||
Value: 10,
|
||||
Aliases: []string{"P"},
|
||||
Usage: "Domain name priority value (e.g. 100)",
|
||||
Destination: &DNSPriority,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// EnsureDNSProvider ensures a DNS provider is chosen.
|
||||
func EnsureDNSProvider() error {
|
||||
if DNSProvider == "" && !NoInput {
|
||||
prompt := &survey.Select{
|
||||
Message: "Select DNS provider",
|
||||
Options: []string{"gandi"},
|
||||
}
|
||||
|
||||
if err := survey.AskOne(prompt, &DNSProvider); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if DNSProvider == "" {
|
||||
return fmt.Errorf("missing DNS provider?")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureDNSTypeFlag ensures a DNS type flag is present.
|
||||
func EnsureDNSTypeFlag(c *cli.Context) error {
|
||||
if DNSType == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "Specify DNS record type",
|
||||
Default: "A",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &DNSType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if DNSType == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no record type provided"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureDNSNameFlag ensures a DNS name flag is present.
|
||||
func EnsureDNSNameFlag(c *cli.Context) error {
|
||||
if DNSName == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "Specify DNS record name",
|
||||
Default: "mysubdomain",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &DNSName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if DNSName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no record name provided"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureDNSValueFlag ensures a DNS value flag is present.
|
||||
func EnsureDNSValueFlag(c *cli.Context) error {
|
||||
if DNSValue == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "Specify DNS record value",
|
||||
Default: "192.168.1.2",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &DNSValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if DNSName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no record value provided"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package domain
|
||||
package record
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -13,17 +13,18 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// DomainListCommand lists domains.
|
||||
var DomainListCommand = &cli.Command{
|
||||
// RecordListCommand lists domains.
|
||||
var RecordListCommand = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List domain name records for a zone",
|
||||
Usage: "List domain name records",
|
||||
Aliases: []string{"ls"},
|
||||
ArgsUsage: "<zone>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DNSProviderFlag,
|
||||
},
|
||||
Description: `
|
||||
This command lists all domain name records managed by a 3rd party provider.
|
||||
This command lists all domain name records managed by a 3rd party provider for
|
||||
a specific zone.
|
||||
|
||||
You must specify a zone (e.g. example.com) under which your domain name records
|
||||
are listed. This zone must already be created on your provider account.
|
|
@ -1,4 +1,4 @@
|
|||
package domain
|
||||
package record
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -15,14 +15,19 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// DomainCreateCommand lists domains.
|
||||
var DomainCreateCommand = &cli.Command{
|
||||
Name: "create",
|
||||
// RecordCreateCommand lists domains.
|
||||
var RecordCreateCommand = &cli.Command{
|
||||
Name: "new",
|
||||
Usage: "Create a new domain record",
|
||||
Aliases: []string{"c"},
|
||||
ArgsUsage: "<zone> <type> <name> <value> [<ttl>] [<priority>]",
|
||||
Aliases: []string{"n"},
|
||||
ArgsUsage: "<zone>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DNSProviderFlag,
|
||||
internal.DNSTypeFlag,
|
||||
internal.DNSNameFlag,
|
||||
internal.DNSValueFlag,
|
||||
internal.DNSTTLFlag,
|
||||
internal.DNSPriorityFlag,
|
||||
},
|
||||
Description: `
|
||||
This command creates a new domain name record for a specific zone.
|
||||
|
@ -32,9 +37,11 @@ are listed. This zone must already be created on your provider account.
|
|||
|
||||
Example:
|
||||
|
||||
abra domain create -p gandi foo.com A myapp 192.168.178.44
|
||||
abra record new foo.com -p gandi -t A -n myapp -v 192.168.178.44
|
||||
|
||||
Which means you can then deploy an app against "myapp.foo.com" successfully.
|
||||
You may also invoke this command in "wizard" mode and be prompted for input
|
||||
|
||||
abra record new
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
zone := c.Args().First()
|
||||
|
@ -42,30 +49,8 @@ Which means you can then deploy an app against "myapp.foo.com" successfully.
|
|||
internal.ShowSubcommandHelpAndError(c, errors.New("no zone provided"))
|
||||
}
|
||||
|
||||
recordType := c.Args().Get(1)
|
||||
recordName := c.Args().Get(2)
|
||||
recordValue := c.Args().Get(3)
|
||||
recordTTL := c.Args().Get(4)
|
||||
recordPriority := c.Args().Get(5)
|
||||
|
||||
if recordType == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no type provided"))
|
||||
}
|
||||
if recordName == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no name provided"))
|
||||
}
|
||||
if recordValue == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no value provided"))
|
||||
}
|
||||
|
||||
if recordTTL == "" {
|
||||
recordTTL = "86400"
|
||||
}
|
||||
|
||||
if recordType == "MX" || recordType == "SRV" || recordType == "URI" {
|
||||
if recordPriority == "" {
|
||||
logrus.Fatal("record priority must be set when using MX/SRV/URI records")
|
||||
}
|
||||
if err := internal.EnsureDNSProvider(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -80,24 +65,27 @@ Which means you can then deploy an app against "myapp.foo.com" successfully.
|
|||
logrus.Fatalf("'%s' is not a supported DNS provider", internal.DNSProvider)
|
||||
}
|
||||
|
||||
ttl, err := strconv.Atoi(recordTTL)
|
||||
if err != nil {
|
||||
if err := internal.EnsureDNSTypeFlag(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := internal.EnsureDNSNameFlag(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := internal.EnsureDNSValueFlag(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
record := libdns.Record{
|
||||
Type: recordType,
|
||||
Name: recordName,
|
||||
Value: recordValue,
|
||||
TTL: time.Duration(ttl),
|
||||
Type: internal.DNSType,
|
||||
Name: internal.DNSName,
|
||||
Value: internal.DNSValue,
|
||||
TTL: time.Duration(internal.DNSTTL),
|
||||
}
|
||||
|
||||
if recordType == "MX" || recordType == "SRV" || recordType == "URI" {
|
||||
priority, err := strconv.Atoi(recordPriority)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
record.Priority = priority
|
||||
if internal.DNSType == "MX" || internal.DNSType == "SRV" || internal.DNSType == "URI" {
|
||||
record.Priority = internal.DNSPriority
|
||||
}
|
||||
|
||||
records, err := provider.GetRecords(c.Context, zone)
|
||||
|
@ -120,7 +108,7 @@ Which means you can then deploy an app against "myapp.foo.com" successfully.
|
|||
)
|
||||
|
||||
if len(createdRecords) == 0 {
|
||||
logrus.Fatal("provider library reports no record created?")
|
||||
logrus.Fatal("provider library reports that no record was created?")
|
||||
}
|
||||
|
||||
createdRecord := createdRecords[0]
|
|
@ -1,15 +1,15 @@
|
|||
package domain
|
||||
package record
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// DomainCommand supports managing DNS entries.
|
||||
var DomainCommand = &cli.Command{
|
||||
Name: "domain",
|
||||
Usage: "Manage domains via 3rd party providers",
|
||||
Aliases: []string{"d"},
|
||||
ArgsUsage: "<domain>",
|
||||
// RecordCommand supports managing DNS entries.
|
||||
var RecordCommand = &cli.Command{
|
||||
Name: "record",
|
||||
Usage: "Manage domain name records via 3rd party providers",
|
||||
Aliases: []string{"rc"},
|
||||
ArgsUsage: "<record>",
|
||||
Description: `
|
||||
This command supports managing domain name records via 3rd party providers such
|
||||
as Gandi DNS. It supports listing, creating and removing all types of records
|
||||
|
@ -31,8 +31,8 @@ allows to implement new provider support easily.
|
|||
|
||||
`,
|
||||
Subcommands: []*cli.Command{
|
||||
DomainListCommand,
|
||||
DomainCreateCommand,
|
||||
DomainRemoveCommand,
|
||||
RecordListCommand,
|
||||
RecordCreateCommand,
|
||||
RecordRemoveCommand,
|
||||
},
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package domain
|
||||
package record
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -15,29 +15,32 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// DomainRemoveCommand lists domains.
|
||||
var DomainRemoveCommand = &cli.Command{
|
||||
// RecordRemoveCommand lists domains.
|
||||
var RecordRemoveCommand = &cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "Remove domain name records for a zone",
|
||||
Usage: "Remove a domain name record",
|
||||
Aliases: []string{"rm"},
|
||||
ArgsUsage: "<zone> <type> <name>",
|
||||
ArgsUsage: "<zone>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DNSProviderFlag,
|
||||
internal.DNSTypeFlag,
|
||||
internal.DNSNameFlag,
|
||||
},
|
||||
Description: `
|
||||
This command removes a new domain name record for a specific zone.
|
||||
This command removes a domain name record for a specific zone.
|
||||
|
||||
You must specify a zone (e.g. example.com) under which your domain name records
|
||||
are listed. This zone must already be created on your provider account.
|
||||
|
||||
The "<id>" can be retrieved by running "abra domain list <zone>". This can be
|
||||
used then in this command for deletion of the record.
|
||||
It uses the type of record and name to match existing records and choose one
|
||||
for deletion. You must specify a zone (e.g. example.com) under which your
|
||||
domain name records are listed. This zone must already be created on your
|
||||
provider account.
|
||||
|
||||
Example:
|
||||
|
||||
abra domain remove -p gandi foo.com A myapp
|
||||
abra record remove foo.com -p gandi -t A -n myapp
|
||||
|
||||
Which means that the domain name record of type A for myapp.foo.com will be deleted.
|
||||
You may also invoke this command in "wizard" mode and be prompted for input
|
||||
|
||||
abra record rm
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
zone := c.Args().First()
|
||||
|
@ -45,14 +48,8 @@ Which means that the domain name record of type A for myapp.foo.com will be dele
|
|||
internal.ShowSubcommandHelpAndError(c, errors.New("no zone provided"))
|
||||
}
|
||||
|
||||
recordType := c.Args().Get(1)
|
||||
recordName := c.Args().Get(2)
|
||||
|
||||
if recordType == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no type provided"))
|
||||
}
|
||||
if recordName == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no name provided"))
|
||||
if err := internal.EnsureDNSProvider(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -67,6 +64,14 @@ Which means that the domain name record of type A for myapp.foo.com will be dele
|
|||
logrus.Fatalf("'%s' is not a supported DNS provider", internal.DNSProvider)
|
||||
}
|
||||
|
||||
if err := internal.EnsureDNSTypeFlag(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := internal.EnsureDNSNameFlag(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
records, err := provider.GetRecords(c.Context, zone)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
|
@ -74,7 +79,7 @@ Which means that the domain name record of type A for myapp.foo.com will be dele
|
|||
|
||||
var toDelete libdns.Record
|
||||
for _, record := range records {
|
||||
if record.Type == recordType && record.Name == recordName {
|
||||
if record.Type == internal.DNSType && record.Name == internal.DNSName {
|
||||
toDelete = record
|
||||
break
|
||||
}
|
Loading…
Reference in New Issue