refactor!: drop "record" & "server new" command

These were alpha prototypes and we'll reconsider once other layers of
Abra are more stable.
This commit is contained in:
2023-09-14 10:02:43 +02:00
parent b1888dcf0f
commit ab7edd2a62
15 changed files with 6 additions and 1347 deletions

View File

@ -1,261 +0,0 @@
package server
import (
"context"
"fmt"
"strings"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/libcapsul"
"github.com/AlecAivazis/survey/v2"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
func newHetznerCloudVPS(c *cli.Context) error {
if err := internal.EnsureNewHetznerCloudVPSFlags(c); err != nil {
return err
}
client := hcloud.NewClient(hcloud.WithToken(internal.HetznerCloudAPIToken))
var sshKeysRaw []string
var sshKeys []*hcloud.SSHKey
for _, sshKey := range c.StringSlice("hetzner-ssh-keys") {
if sshKey == "" {
continue
}
sshKey, _, err := client.SSHKey.GetByName(context.Background(), sshKey)
if err != nil {
return err
}
sshKeys = append(sshKeys, sshKey)
sshKeysRaw = append(sshKeysRaw, sshKey.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},
}
sshKeyIDs := strings.Join(sshKeysRaw, "\n")
if sshKeyIDs == "" {
sshKeyIDs = "N/A (password auth)"
}
tableColumns := []string{"name", "type", "image", "ssh-keys", "location"}
table := formatter.CreateTable(tableColumns)
table.Append([]string{
internal.HetznerCloudName,
internal.HetznerCloudType,
internal.HetznerCloudImage,
sshKeyIDs,
internal.HetznerCloudLocation,
})
table.Render()
response := false
prompt := &survey.Confirm{
Message: "continue with hetzner cloud VPS creation?",
}
if err := survey.AskOne(prompt, &response); err != nil {
return err
}
if !response {
logrus.Fatal("exiting as requested")
}
res, _, err := client.Server.Create(context.Background(), serverOpts)
if err != nil {
return err
}
var rootPassword string
if len(sshKeys) > 0 {
rootPassword = "N/A (using SSH keys)"
} else {
rootPassword = res.RootPassword
}
ip := res.Server.PublicNet.IPv4.IP.String()
fmt.Println(fmt.Sprintf(`
Your new Hetzner Cloud VPS has successfully been created! Here are the details:
name: %s
IP address: %s
root password: %s
You can access this new VPS via SSH using the following command:
ssh root@%s
Please note, this server is not managed by Abra yet (i.e. "abra server ls" will
not list this server)! You will need to assign a domain name record (manually
or by using "abra record new") and add the server to your Abra configuration
("abra server add") to have a working server that you can deploy Co-op Cloud
apps to.
When setting up domain name records, you probably want to set up the following
2 A records. This supports deploying apps to your root domain (e.g.
example.com) and other apps on sub-domains (e.g. foo.example.com,
bar.example.com).
@ 1800 IN A %s
* 1800 IN A %s
`,
internal.HetznerCloudName, ip, rootPassword,
ip, ip, ip,
))
return nil
}
func newCapsulVPS(c *cli.Context) error {
if err := internal.EnsureNewCapsulVPSFlags(c); err != nil {
return err
}
capsulCreateURL := fmt.Sprintf("https://%s/api/capsul/create", internal.CapsulInstanceURL)
var sshKeys []string
for _, sshKey := range c.StringSlice("capsul-ssh-keys") {
if sshKey == "" {
continue
}
sshKeys = append(sshKeys, sshKey)
}
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()
response := false
prompt := &survey.Confirm{
Message: "continue with capsul creation?",
}
if err := survey.AskOne(prompt, &response); err != nil {
return err
}
if !response {
logrus.Fatal("exiting as requested")
}
capsulClient := libcapsul.New(capsulCreateURL, internal.CapsulAPIToken)
resp, err := capsulClient.Create(
internal.CapsulName,
internal.CapsulType,
internal.CapsulImage,
sshKeys,
)
if err != nil {
return err
}
fmt.Println(fmt.Sprintf(`
Your new Capsul has successfully been created! Here are the details:
Capsul name: %s
Capsul ID: %v
You will need to log into your Capsul instance web interface to retrieve the IP
address. You can learn all about how to get SSH access to your new Capsul on:
%s/about-ssh
Please note, this server is not managed by Abra yet (i.e. "abra server ls" will
not list this server)! You will need to assign a domain name record (manually
or by using "abra record new") and add the server to your Abra configuration
("abra server add") to have a working server that you can deploy Co-op Cloud
apps to.
When setting up domain name records, you probably want to set up the following
2 A records. This supports deploying apps to your root domain (e.g.
example.com) and other apps on sub-domains (e.g. foo.example.com,
bar.example.com).
@ 1800 IN A <your-capsul-ip>
* 1800 IN A <your-capsul-ip>
`, internal.CapsulName, resp.ID, internal.CapsulInstanceURL))
return nil
}
var serverNewCommand = cli.Command{
Name: "new",
Aliases: []string{"n"},
Usage: "Create a new server using a 3rd party provider",
Description: `
Create 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
API tokens are read from the environment if specified, e.g.
export HCLOUD_TOKEN=...
`,
Flags: []cli.Flag{
internal.DebugFlag,
internal.NoInputFlag,
internal.ServerProviderFlag,
internal.OfflineFlag,
// Capsul
internal.CapsulInstanceURLFlag,
internal.CapsulTypeFlag,
internal.CapsulImageFlag,
internal.CapsulSSHKeysFlag,
internal.CapsulAPITokenFlag,
// Hetzner
internal.HetznerCloudNameFlag,
internal.HetznerCloudTypeFlag,
internal.HetznerCloudImageFlag,
internal.HetznerCloudSSHKeysFlag,
internal.HetznerCloudLocationFlag,
internal.HetznerCloudAPITokenFlag,
},
Before: internal.SubCommandBefore,
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
},
}

View File

@ -1,8 +1,6 @@
package server
import (
"context"
"fmt"
"os"
"path/filepath"
@ -10,168 +8,31 @@ import (
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
"github.com/AlecAivazis/survey/v2"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var rmServer bool
var rmServerFlag = &cli.BoolFlag{
Name: "server, s",
Usage: "remove the actual server also",
Destination: &rmServer,
}
func rmHetznerCloudVPS(c *cli.Context) error {
if internal.HetznerCloudName == "" && !internal.NoInput {
prompt := &survey.Input{
Message: "specify hetzner cloud VPS name",
}
if err := survey.AskOne(prompt, &internal.HetznerCloudName); err != nil {
return err
}
}
if internal.HetznerCloudAPIToken == "" && !internal.NoInput {
token, ok := os.LookupEnv("HCLOUD_TOKEN")
if !ok {
prompt := &survey.Input{
Message: "specify hetzner cloud API token",
}
if err := survey.AskOne(prompt, &internal.HetznerCloudAPIToken); err != nil {
return err
}
} else {
internal.HetznerCloudAPIToken = token
}
}
client := hcloud.NewClient(hcloud.WithToken(internal.HetznerCloudAPIToken))
server, _, err := client.Server.Get(context.Background(), internal.HetznerCloudName)
if err != nil {
return err
}
if server == nil {
logrus.Fatalf("library provider reports that %s doesn't exist?", internal.HetznerCloudName)
}
fmt.Println(fmt.Sprintf(`
You have requested that Abra delete the following server (%s). Please be
absolutely sure that this is indeed the server that you would like to have
removed. There will be no going back once you confirm, the server will be
destroyed.
`, server.Name))
tableColumns := []string{"name", "type", "image", "location"}
table := formatter.CreateTable(tableColumns)
table.Append([]string{
server.Name,
server.ServerType.Name,
server.Image.Name,
server.Datacenter.Name,
})
table.Render()
response := false
prompt := &survey.Confirm{
Message: "continue with hetzner cloud VPS removal?",
}
if err := survey.AskOne(prompt, &response); err != nil {
return err
}
if !response {
logrus.Fatal("exiting as requested")
}
_, err = client.Server.Delete(context.Background(), server)
if err != nil {
return err
}
logrus.Infof("%s has been deleted from your hetzner cloud account", internal.HetznerCloudName)
return nil
}
var serverRemoveCommand = cli.Command{
Name: "remove",
Aliases: []string{"rm"},
ArgsUsage: "[<server>]",
Usage: "Remove a managed server",
Description: `
Remova a server from Abra management.
Description: `Remove a managed server.
Depending on whether you used a 3rd party provider to create this server ("abra
server new"), you can also destroy the virtual server as well. Pass
"--server/-s" to tell Abra to try to delete this VPS.
Otherwise, Abra will remove the internal bookkeeping (~/.abra/servers/...) and
underlying client connection context. This server will then be lost in time,
like tears in rain.
Abra will remove the internal bookkeeping (~/.abra/servers/...) and underlying
client connection context. This server will then be lost in time, like tears in
rain.
`,
Flags: []cli.Flag{
internal.DebugFlag,
internal.NoInputFlag,
rmServerFlag,
internal.ServerProviderFlag,
internal.OfflineFlag,
// Hetzner
internal.HetznerCloudNameFlag,
internal.HetznerCloudAPITokenFlag,
},
Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete,
Action: func(c *cli.Context) error {
serverName := internal.ValidateServer(c)
warnMsg := `Did not pass -s/--server for actual server deletion, prompting!
Abra doesn't currently know if it helped you create this server with one of the
3rd party integrations (e.g. Capsul). You have a choice here to actually,
really and finally destroy this server using those integrations. If you want to
do this, choose Yes.
If you just want to remove the server config files & context, choose No.
`
if !rmServer {
logrus.Warn(fmt.Sprintf(warnMsg))
response := false
prompt := &survey.Confirm{
Message: "delete actual live server?",
}
if err := survey.AskOne(prompt, &response); err != nil {
logrus.Fatal(err)
}
if response {
logrus.Info("setting -s/--server and attempting to remove actual server")
rmServer = true
}
}
if rmServer {
if err := internal.EnsureServerProvider(); err != nil {
logrus.Fatal(err)
}
switch internal.ServerProvider {
case "capsul":
logrus.Warn("capsul provider does not support automatic removal yet, sorry!")
case "hetzner-cloud":
if err := rmHetznerCloudVPS(c); err != nil {
logrus.Fatal(err)
}
}
}
if err := client.DeleteContext(serverName); err != nil {
logrus.Fatal(err)
}

View File

@ -9,16 +9,7 @@ var ServerCommand = cli.Command{
Name: "server",
Aliases: []string{"s"},
Usage: "Manage servers",
Description: `
Create, manage and remove servers using 3rd party integrations.
Servers can be created from scratch using the "abra server new" command. If you
already have a server, you can add it to your configuration using "abra server
add". Abra can provision servers so that they are ready to deploy Co-op Cloud
recipes, see available flags on "abra server add" for more.
`,
Subcommands: []cli.Command{
serverNewCommand,
serverAddCommand,
serverListCommand,
serverRemoveCommand,