diff --git a/cli/cli.go b/cli/cli.go index 4d30f54f0..6b138933e 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -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{ diff --git a/cli/internal/common.go b/cli/internal/common.go index e0a97e53d..6d78aa44a 100644 --- a/cli/internal/common.go +++ b/cli/internal/common.go @@ -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, +} diff --git a/cli/internal/domain.go b/cli/internal/domain.go new file mode 100644 index 000000000..91a0a1c26 --- /dev/null +++ b/cli/internal/domain.go @@ -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 +} diff --git a/cli/domain/list.go b/cli/record/list.go similarity index 90% rename from cli/domain/list.go rename to cli/record/list.go index 98ff9d458..8b8e35762 100644 --- a/cli/domain/list.go +++ b/cli/record/list.go @@ -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: "", 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. diff --git a/cli/domain/create.go b/cli/record/new.go similarity index 59% rename from cli/domain/create.go rename to cli/record/new.go index 4b88bffb6..1fa87af8f 100644 --- a/cli/domain/create.go +++ b/cli/record/new.go @@ -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: " [] []", + Aliases: []string{"n"}, + ArgsUsage: "", 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] diff --git a/cli/domain/domain.go b/cli/record/record.go similarity index 73% rename from cli/domain/domain.go rename to cli/record/record.go index 7f8b9bad0..df62e813f 100644 --- a/cli/domain/domain.go +++ b/cli/record/record.go @@ -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: "", +// RecordCommand supports managing DNS entries. +var RecordCommand = &cli.Command{ + Name: "record", + Usage: "Manage domain name records via 3rd party providers", + Aliases: []string{"rc"}, + ArgsUsage: "", 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, }, } diff --git a/cli/domain/remove.go b/cli/record/remove.go similarity index 67% rename from cli/domain/remove.go rename to cli/record/remove.go index c3c7b99dd..97bead134 100644 --- a/cli/domain/remove.go +++ b/cli/record/remove.go @@ -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: " ", + ArgsUsage: "", 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 "" can be retrieved by running "abra domain list ". 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 }