package server import ( "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" ) 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("ssh-keys") { sshKey, _, err := client.SSHKey.GetByName(c.Context, 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}, } 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() 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") } 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 } 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") { 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 } 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{ Name: "new", Aliases: []string{"n"}, Usage: "Create a new server using a 3rd party provider", Description: ` 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: "", 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 }, }