refactor!: abra server interface more coherent
This follows our app new UX and interactive mode design.
This commit is contained in:
parent
94c7f59113
commit
313e3beb1e
@ -132,3 +132,130 @@ var DNSPriorityFlag = &cli.IntFlag{
|
||||
Usage: "Domain name priority value",
|
||||
Destination: &DNSPriority,
|
||||
}
|
||||
|
||||
var ServerProvider string
|
||||
|
||||
var ServerProviderFlag = &cli.StringFlag{
|
||||
Name: "provider",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "3rd party server provider",
|
||||
Destination: &ServerProvider,
|
||||
}
|
||||
|
||||
var CapsulInstanceURL string
|
||||
|
||||
var CapsulInstanceURLFlag = &cli.StringFlag{
|
||||
Name: "capsul-url",
|
||||
Value: "",
|
||||
Aliases: []string{"cu"},
|
||||
Usage: "Capsul instance URL",
|
||||
Destination: &CapsulInstanceURL,
|
||||
}
|
||||
|
||||
var CapsulName string
|
||||
|
||||
var CapsulNameFlag = &cli.StringFlag{
|
||||
Name: "capsul-name",
|
||||
Value: "",
|
||||
Aliases: []string{"cn"},
|
||||
Usage: "Capsul name",
|
||||
Destination: &CapsulName,
|
||||
}
|
||||
|
||||
var CapsulType string
|
||||
|
||||
var CapsulTypeFlag = &cli.StringFlag{
|
||||
Name: "capsul-type",
|
||||
Value: "",
|
||||
Aliases: []string{"ct"},
|
||||
Usage: "Capsul type",
|
||||
Destination: &CapsulType,
|
||||
}
|
||||
|
||||
var CapsulImage string
|
||||
|
||||
var CapsulImageFlag = &cli.StringFlag{
|
||||
Name: "capsul-image",
|
||||
Value: "debian10",
|
||||
Aliases: []string{"ci"},
|
||||
Usage: "Capsul image",
|
||||
Destination: &CapsulImage,
|
||||
}
|
||||
|
||||
var CapsulSSHKeys cli.StringSlice
|
||||
|
||||
var CapsulSSHKeysFlag = &cli.StringSliceFlag{
|
||||
Name: "capsul-ssh-keys",
|
||||
Aliases: []string{"cs"},
|
||||
Usage: "Capsul SSH key (e.g. me@foo.com)",
|
||||
Destination: &CapsulSSHKeys,
|
||||
}
|
||||
|
||||
var CapsulAPIToken string
|
||||
|
||||
var CapsulAPITokenFlag = &cli.StringFlag{
|
||||
Name: "capsul-token",
|
||||
Aliases: []string{"ca"},
|
||||
Usage: "Capsul API token",
|
||||
EnvVars: []string{"CAPSUL_TOKEN"},
|
||||
Destination: &CapsulAPIToken,
|
||||
}
|
||||
|
||||
var HetznerCloudName string
|
||||
|
||||
var HetznerCloudNameFlag = &cli.StringFlag{
|
||||
Name: "hetzner-name",
|
||||
Value: "",
|
||||
Aliases: []string{"hn"},
|
||||
Usage: "hetzner cloud name",
|
||||
Destination: &HetznerCloudName,
|
||||
}
|
||||
|
||||
var HetznerCloudType string
|
||||
|
||||
var HetznerCloudTypeFlag = &cli.StringFlag{
|
||||
Name: "hetzner-type",
|
||||
Aliases: []string{"ht"},
|
||||
Usage: "hetzner cloud type",
|
||||
Destination: &HetznerCloudType,
|
||||
Value: "cx11",
|
||||
}
|
||||
|
||||
var HetznerCloudImage string
|
||||
|
||||
var HetznerCloudImageFlag = &cli.StringFlag{
|
||||
Name: "hetzner-image",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "hetzner cloud image",
|
||||
Value: "debian-10",
|
||||
Destination: &HetznerCloudImage,
|
||||
}
|
||||
|
||||
var HetznerCloudSSHKeys cli.StringSlice
|
||||
|
||||
var HetznerCloudSSHKeysFlag = &cli.StringSliceFlag{
|
||||
Name: "hetzner-ssh-keys",
|
||||
Aliases: []string{"hs"},
|
||||
Usage: "hetzner cloud SSH keys (e.g. me@foo.com)",
|
||||
Destination: &HetznerCloudSSHKeys,
|
||||
}
|
||||
|
||||
var HetznerCloudLocation string
|
||||
|
||||
var HetznerCloudLocationFlag = &cli.StringFlag{
|
||||
Name: "hetzner-location",
|
||||
Aliases: []string{"hl"},
|
||||
Usage: "hetzner cloud server location",
|
||||
Value: "hel1",
|
||||
Destination: &HetznerCloudLocation,
|
||||
}
|
||||
|
||||
var HetznerCloudAPIToken string
|
||||
|
||||
var HetznerCloudAPITokenFlag = &cli.StringFlag{
|
||||
Name: "hetzner-token",
|
||||
Aliases: []string{"ha"},
|
||||
Usage: "hetzner cloud API token",
|
||||
EnvVars: []string{"HCLOUD_TOKEN"},
|
||||
Destination: &HetznerCloudAPIToken,
|
||||
}
|
||||
|
191
cli/internal/server.go
Normal file
191
cli/internal/server.go
Normal file
@ -0,0 +1,191 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// EnsureServerProvider ensures a 3rd party server provider is chosen.
|
||||
func EnsureServerProvider() error {
|
||||
if ServerProvider == "" && !NoInput {
|
||||
prompt := &survey.Select{
|
||||
Message: "Select server provider",
|
||||
Options: []string{"capsul", "hetzner-cloud"},
|
||||
}
|
||||
|
||||
if err := survey.AskOne(prompt, &ServerProvider); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if ServerProvider == "" {
|
||||
return fmt.Errorf("missing server provider?")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureCapsulNewFlags ensure all flags are present.
|
||||
func EnsureNewCapsulVPSFlags(c *cli.Context) error {
|
||||
if CapsulName == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify capsul name",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &CapsulName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if CapsulInstanceURL == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify capsul instance URL",
|
||||
Default: "yolo.servers.coop",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &CapsulInstanceURL); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if CapsulType == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify capsul type",
|
||||
Default: "f1-xs",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &CapsulType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if CapsulImage == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify capsul image",
|
||||
Default: "debian10",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &CapsulImage); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(CapsulSSHKeys.Value()) == 0 && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify capsul SSH keys",
|
||||
Default: "me@foo.com,you@bar.com",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &CapsulSSHKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if CapsulAPIToken == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify capsul API token",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &CapsulAPIToken); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if CapsulName == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing capsul name?"))
|
||||
}
|
||||
if CapsulInstanceURL == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing capsul instance url?"))
|
||||
}
|
||||
if CapsulType == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing capsul type?"))
|
||||
}
|
||||
if CapsulImage == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing capsul image?"))
|
||||
}
|
||||
if len(CapsulSSHKeys.Value()) == 0 {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing capsul ssh keys?"))
|
||||
}
|
||||
if CapsulAPIToken == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing capsul API token?"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureNewHetznerCloudVPSFlags ensure all flags are present.
|
||||
func EnsureNewHetznerCloudVPSFlags(c *cli.Context) error {
|
||||
if HetznerCloudName == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify hetzner cloud VPS name",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &HetznerCloudName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if HetznerCloudType == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify hetzner cloud VPS type",
|
||||
Default: "cx11",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &HetznerCloudType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if HetznerCloudImage == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify hetzner cloud VPS image",
|
||||
Default: "debian-10",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &HetznerCloudImage); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(HetznerCloudSSHKeys.Value()) == 0 && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify hetzner cloud SSH keys",
|
||||
Default: "me@foo.com,you@bar.com",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &HetznerCloudSSHKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if HetznerCloudLocation == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify hetzner cloud VPS location",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &HetznerCloudLocation); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if HetznerCloudAPIToken == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "specify hetzner cloud API token",
|
||||
}
|
||||
if err := survey.AskOne(prompt, &HetznerCloudAPIToken); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if HetznerCloudName == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing hetzner cloud VPS name?"))
|
||||
}
|
||||
if HetznerCloudType == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing hetzner cloud VPS type?"))
|
||||
}
|
||||
if HetznerCloudImage == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing hetzner cloud image?"))
|
||||
}
|
||||
if len(HetznerCloudSSHKeys.Value()) == 0 {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing hetzner cloud ssh keys?"))
|
||||
}
|
||||
if HetznerCloudLocation == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing hetzner cloud VPS location?"))
|
||||
}
|
||||
if HetznerCloudAPIToken == "" {
|
||||
ShowSubcommandHelpAndError(c, fmt.Errorf("missing hetzner cloud API token?"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -15,8 +15,8 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// RecordCreateCommand lists domains.
|
||||
var RecordCreateCommand = &cli.Command{
|
||||
// RecordNewCommand creates a new domain name record.
|
||||
var RecordNewCommand = &cli.Command{
|
||||
Name: "new",
|
||||
Usage: "Create a new domain record",
|
||||
Aliases: []string{"n"},
|
||||
|
@ -23,16 +23,16 @@ You need an account with such a provider already. Typically, you need to
|
||||
provide an API token on the Abra command-line when using these commands so that
|
||||
you can authenticate with your provider account.
|
||||
|
||||
Any new provider can be integrated, we welcome change sets. See the underlying
|
||||
DNS library documentation for more. It supports many existing providers and
|
||||
allows to implement new provider support easily.
|
||||
New providers can be integrated, we welcome change sets. See the underlying DNS
|
||||
library documentation for more. It supports many existing providers and allows
|
||||
to implement new provider support easily.
|
||||
|
||||
https://pkg.go.dev/github.com/libdns/libdns
|
||||
|
||||
`,
|
||||
Subcommands: []*cli.Command{
|
||||
RecordListCommand,
|
||||
RecordCreateCommand,
|
||||
RecordNewCommand,
|
||||
RecordRemoveCommand,
|
||||
},
|
||||
}
|
||||
|
@ -1,207 +1,148 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"coopcloud.tech/abra/cli/formatter"
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/libcapsul"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/hetznercloud/hcloud-go/hcloud"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var hetznerCloudType string
|
||||
var hetznerCloudImage string
|
||||
var hetznerCloudSSHKeys cli.StringSlice
|
||||
var hetznerCloudLocation string
|
||||
var hetznerCloudAPIToken string
|
||||
var serverNewHetznerCloudCommand = &cli.Command{
|
||||
Name: "hetzner",
|
||||
Usage: "Create a new Hetzner virtual server",
|
||||
ArgsUsage: "<name>",
|
||||
Description: `
|
||||
Create a new Hetzner virtual server.
|
||||
func newHetznerCloudVPS(c *cli.Context) error {
|
||||
if err := internal.EnsureNewHetznerCloudVPSFlags(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
This command uses the uses the Hetzner Cloud API bindings to send a server
|
||||
creation request. You must already have a Hetzner Cloud account and an account
|
||||
API token before using this command.
|
||||
client := hcloud.NewClient(hcloud.WithToken(internal.HetznerCloudAPIToken))
|
||||
|
||||
Your token can be loaded from the environment using the HCLOUD_TOKEN
|
||||
environment variable or otherwise passing the "--token/-T" flag.
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "type",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Server type",
|
||||
Destination: &hetznerCloudType,
|
||||
Value: "cx11",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "image",
|
||||
Aliases: []string{"i"},
|
||||
Usage: "Image type",
|
||||
Value: "debian-10",
|
||||
Destination: &hetznerCloudImage,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "ssh-keys",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "SSH keys",
|
||||
Destination: &hetznerCloudSSHKeys,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "location",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "Server location",
|
||||
Value: "hel1",
|
||||
Destination: &hetznerCloudLocation,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Aliases: []string{"T"},
|
||||
Usage: "Hetzner Cloud API token",
|
||||
EnvVars: []string{"HCLOUD_TOKEN"},
|
||||
Destination: &hetznerCloudAPIToken,
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
name := c.Args().First()
|
||||
if name == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no name provided"))
|
||||
}
|
||||
|
||||
if hetznerCloudAPIToken == "" {
|
||||
logrus.Fatal("Hetzner Cloud API token is missing")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
client := hcloud.NewClient(hcloud.WithToken(hetznerCloudAPIToken))
|
||||
|
||||
logrus.Debugf("successfully created hetzner cloud API client")
|
||||
|
||||
var sshKeys []*hcloud.SSHKey
|
||||
for _, sshKey := range c.StringSlice("ssh-keys") {
|
||||
sshKey, _, err := client.SSHKey.GetByName(ctx, sshKey)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
sshKeys = append(sshKeys, sshKey)
|
||||
}
|
||||
|
||||
serverOpts := hcloud.ServerCreateOpts{
|
||||
Name: name,
|
||||
ServerType: &hcloud.ServerType{Name: hetznerCloudType},
|
||||
Image: &hcloud.Image{Name: hetznerCloudImage},
|
||||
SSHKeys: sshKeys,
|
||||
Location: &hcloud.Location{Name: hetznerCloudLocation},
|
||||
}
|
||||
res, _, err := client.Server.Create(ctx, serverOpts)
|
||||
var sshKeysRaw []string
|
||||
var sshKeys []*hcloud.SSHKey
|
||||
for _, sshKey := range c.StringSlice("ssh-keys") {
|
||||
sshKey, _, err := client.SSHKey.GetByName(c.Context, sshKey)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return err
|
||||
}
|
||||
sshKeys = append(sshKeys, sshKey)
|
||||
sshKeysRaw = append(sshKeysRaw, sshKey.Name)
|
||||
}
|
||||
|
||||
logrus.Debugf("new server '%s' created", name)
|
||||
serverOpts := hcloud.ServerCreateOpts{
|
||||
Name: internal.HetznerCloudName,
|
||||
ServerType: &hcloud.ServerType{Name: internal.HetznerCloudType},
|
||||
Image: &hcloud.Image{Name: internal.HetznerCloudImage},
|
||||
SSHKeys: sshKeys,
|
||||
Location: &hcloud.Location{Name: internal.HetznerCloudLocation},
|
||||
}
|
||||
|
||||
tableColumns := []string{"Name", "IPv4", "Root Password"}
|
||||
table := formatter.CreateTable(tableColumns)
|
||||
tableColumns := []string{"name", "type", "image", "ssh-keys", "location"}
|
||||
table := formatter.CreateTable(tableColumns)
|
||||
table.Append([]string{
|
||||
internal.HetznerCloudName,
|
||||
internal.HetznerCloudType,
|
||||
internal.HetznerCloudImage,
|
||||
strings.Join(sshKeysRaw, "\n"),
|
||||
internal.HetznerCloudLocation,
|
||||
})
|
||||
table.Render()
|
||||
|
||||
if len(sshKeys) > 0 {
|
||||
table.Append([]string{name, res.Server.PublicNet.IPv4.IP.String(), "N/A (using SSH keys)"})
|
||||
} else {
|
||||
table.Append([]string{name, res.Server.PublicNet.IPv4.IP.String(), res.RootPassword})
|
||||
}
|
||||
response := false
|
||||
prompt := &survey.Confirm{
|
||||
Message: "continue with capsul creation?",
|
||||
}
|
||||
|
||||
table.Render()
|
||||
if err := survey.AskOne(prompt, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
if !response {
|
||||
logrus.Fatal("exiting as requested")
|
||||
}
|
||||
|
||||
res, _, err := client.Server.Create(c.Context, serverOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tableColumns = []string{"name", "ipv4", "root password"}
|
||||
table = formatter.CreateTable(tableColumns)
|
||||
if len(sshKeys) > 0 {
|
||||
table.Append([]string{
|
||||
internal.HetznerCloudName,
|
||||
res.Server.PublicNet.IPv4.IP.String(),
|
||||
"N/A (using SSH keys)",
|
||||
})
|
||||
} else {
|
||||
table.Append([]string{
|
||||
internal.HetznerCloudName,
|
||||
res.Server.PublicNet.IPv4.IP.String(),
|
||||
res.RootPassword,
|
||||
})
|
||||
}
|
||||
table.SetCaption(true, "hetzner cloud creation response")
|
||||
table.Render()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var capsulInstance string
|
||||
var capsulType string
|
||||
var capsulImage string
|
||||
var capsulSSHKey string
|
||||
var capsulAPIToken string
|
||||
var serverNewCapsulCommand = &cli.Command{
|
||||
Name: "capsul",
|
||||
Usage: "Create a new Capsul virtual server",
|
||||
ArgsUsage: "<name>",
|
||||
Description: `
|
||||
Create a new Capsul virtual server.
|
||||
func newCapsulVPS(c *cli.Context) error {
|
||||
if err := internal.EnsureNewCapsulVPSFlags(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
This command uses the uses the Capsul API bindings of your chosen instance to
|
||||
send a server creation request. You must already have an account on your chosen
|
||||
Capsul instance before using this command.
|
||||
capsulCreateURL := fmt.Sprintf("https://%s/api/capsul/create", internal.CapsulInstanceURL)
|
||||
|
||||
Your token can be loaded from the environment using the CAPSUL_TOKEN
|
||||
environment variable or otherwise passing the "--token/-T" flag.
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "instance",
|
||||
Aliases: []string{"I"},
|
||||
Usage: "Capsul instance",
|
||||
Destination: &capsulInstance,
|
||||
Value: "yolo.servers.coop",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "type",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Server type",
|
||||
Value: "f1-xs",
|
||||
Destination: &capsulType,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "image",
|
||||
Aliases: []string{"i"},
|
||||
Usage: "Image type",
|
||||
Value: "debian10",
|
||||
Destination: &capsulImage,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ssh-key",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "SSH key",
|
||||
Value: "",
|
||||
Destination: &capsulSSHKey,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Aliases: []string{"T"},
|
||||
Usage: "Capsul instance API token",
|
||||
EnvVars: []string{"CAPSUL_TOKEN"},
|
||||
Destination: &capsulAPIToken,
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
capsulName := c.Args().First()
|
||||
if capsulName == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no name provided"))
|
||||
}
|
||||
var sshKeys []string
|
||||
for _, sshKey := range c.StringSlice("capsul-ssh-keys") {
|
||||
sshKeys = append(sshKeys, sshKey)
|
||||
}
|
||||
|
||||
if capsulAPIToken == "" {
|
||||
logrus.Fatal("Capsul API token is missing")
|
||||
}
|
||||
tableColumns := []string{"instance", "name", "type", "image", "ssh-keys"}
|
||||
table := formatter.CreateTable(tableColumns)
|
||||
table.Append([]string{
|
||||
internal.CapsulInstanceURL,
|
||||
internal.CapsulName,
|
||||
internal.CapsulType,
|
||||
internal.CapsulImage,
|
||||
strings.Join(sshKeys, "\n"),
|
||||
})
|
||||
table.Render()
|
||||
|
||||
capsulCreateURL := fmt.Sprintf("https://%s/api/capsul/create", capsulInstance)
|
||||
response := false
|
||||
prompt := &survey.Confirm{
|
||||
Message: "continue with capsul creation?",
|
||||
}
|
||||
|
||||
capsulClient := libcapsul.New(capsulCreateURL, capsulAPIToken)
|
||||
resp, err := capsulClient.Create(capsulName, capsulType, capsulImage, capsulSSHKey)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
if err := survey.AskOne(prompt, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tableColumns := []string{"Name", "ID"}
|
||||
table := formatter.CreateTable(tableColumns)
|
||||
table.Append([]string{capsulName, resp.ID})
|
||||
table.Render()
|
||||
if !response {
|
||||
logrus.Fatal("exiting as requested")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
capsulClient := libcapsul.New(capsulCreateURL, internal.CapsulAPIToken)
|
||||
resp, err := capsulClient.Create(
|
||||
internal.CapsulName,
|
||||
internal.CapsulType,
|
||||
internal.CapsulImage,
|
||||
sshKeys,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tableColumns = []string{"Name", "ID"}
|
||||
table = formatter.CreateTable(tableColumns)
|
||||
table.Append([]string{internal.CapsulName, resp.ID})
|
||||
table.SetCaption(true, "capsul creation response")
|
||||
table.Render()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var serverNewCommand = &cli.Command{
|
||||
@ -209,12 +150,52 @@ var serverNewCommand = &cli.Command{
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Create a new server using a 3rd party provider",
|
||||
Description: `
|
||||
Use a provider plugin to create a new server which can then be used to house a
|
||||
new Co-op Cloud installation.
|
||||
This command creates a new server via a 3rd party provider.
|
||||
|
||||
The following providers are supported:
|
||||
|
||||
Capsul https://git.cyberia.club/Cyberia/capsul-flask
|
||||
Hetzner Cloud https://docs.hetzner.com/cloud
|
||||
|
||||
You may invoke this command in "wizard" mode and be prompted for input:
|
||||
|
||||
abra record new
|
||||
`,
|
||||
ArgsUsage: "<provider>",
|
||||
Subcommands: []*cli.Command{
|
||||
serverNewHetznerCloudCommand,
|
||||
serverNewCapsulCommand,
|
||||
Flags: []cli.Flag{
|
||||
internal.ServerProviderFlag,
|
||||
|
||||
// Capsul
|
||||
internal.CapsulInstanceURLFlag,
|
||||
internal.CapsulTypeFlag,
|
||||
internal.CapsulImageFlag,
|
||||
internal.CapsulSSHKeysFlag,
|
||||
internal.CapsulAPITokenFlag,
|
||||
|
||||
// Hetzner
|
||||
internal.HetznerCloudNameFlag,
|
||||
internal.HetznerCloudTypeFlag,
|
||||
internal.HetznerCloudImageFlag,
|
||||
internal.HetznerCloudSSHKeysFlag,
|
||||
internal.HetznerCloudLocationFlag,
|
||||
internal.HetznerCloudAPITokenFlag,
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if err := internal.EnsureServerProvider(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
switch internal.ServerProvider {
|
||||
case "capsul":
|
||||
if err := newCapsulVPS(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
case "hetzner-cloud":
|
||||
if err := newHetznerCloudVPS(c); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -25,7 +25,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
coopcloud.tech/libcapsul v0.0.0-20211020153234-f1386b5cf79d
|
||||
coopcloud.tech/libcapsul v0.0.0-20211022074848-c35e78fe3f3e
|
||||
github.com/Microsoft/hcsshim v0.8.21 // indirect
|
||||
github.com/containerd/containerd v1.5.5 // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -21,8 +21,8 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
coopcloud.tech/libcapsul v0.0.0-20211020153234-f1386b5cf79d h1:5A69AFx2BP5J43Y9SaB9LlAIMLr2SWqbzfgjUh8sgKM=
|
||||
coopcloud.tech/libcapsul v0.0.0-20211020153234-f1386b5cf79d/go.mod h1:HEQ9pSJRsDKabMxPfYCCzpVpAreLoC4Gh4SkVyOaKvk=
|
||||
coopcloud.tech/libcapsul v0.0.0-20211022074848-c35e78fe3f3e h1:o5OZInc5b9esiN4hlfjZY6u0r+qB2iSv/11jnMGuR38=
|
||||
coopcloud.tech/libcapsul v0.0.0-20211022074848-c35e78fe3f3e/go.mod h1:HEQ9pSJRsDKabMxPfYCCzpVpAreLoC4Gh4SkVyOaKvk=
|
||||
coopcloud.tech/tagcmp v0.0.0-20211011140827-4f27c74467eb h1:Jf+Dnna2kXcNQvcA5JMp6d2Uyvg2pIVJfip9+X5FrH0=
|
||||
coopcloud.tech/tagcmp v0.0.0-20211011140827-4f27c74467eb/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
|
Loading…
Reference in New Issue
Block a user