2021-08-02 01:10:41 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-08-03 11:57:12 +00:00
|
|
|
"errors"
|
2021-08-02 13:11:14 +00:00
|
|
|
"fmt"
|
2021-08-02 01:10:41 +00:00
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
"coopcloud.tech/abra/cli/formatter"
|
2021-08-03 11:57:12 +00:00
|
|
|
"coopcloud.tech/abra/cli/internal"
|
2021-10-20 15:25:46 +00:00
|
|
|
"coopcloud.tech/libcapsul"
|
2021-08-02 01:10:41 +00:00
|
|
|
"github.com/hetznercloud/hcloud-go/hcloud"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
)
|
|
|
|
|
2021-08-02 06:36:35 +00:00
|
|
|
var hetznerCloudType string
|
|
|
|
var hetznerCloudImage string
|
|
|
|
var hetznerCloudSSHKeys cli.StringSlice
|
|
|
|
var hetznerCloudLocation string
|
|
|
|
var hetznerCloudAPIToken string
|
2021-08-02 01:10:41 +00:00
|
|
|
var serverNewHetznerCloudCommand = &cli.Command{
|
|
|
|
Name: "hetzner",
|
|
|
|
Usage: "Create a new Hetzner virtual server",
|
|
|
|
ArgsUsage: "<name>",
|
|
|
|
Description: `
|
|
|
|
Create a new Hetzner virtual server.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
Your token can be loaded from the environment using the HCLOUD_TOKEN
|
2021-08-02 01:10:41 +00:00
|
|
|
environment variable or otherwise passing the "--env/-e" flag.
|
|
|
|
`,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "type",
|
|
|
|
Aliases: []string{"t"},
|
|
|
|
Usage: "Server type",
|
2021-08-02 06:36:35 +00:00
|
|
|
Destination: &hetznerCloudType,
|
2021-08-02 01:10:41 +00:00
|
|
|
Value: "cx11",
|
|
|
|
},
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "image",
|
|
|
|
Aliases: []string{"i"},
|
|
|
|
Usage: "Image type",
|
|
|
|
Value: "debian-10",
|
2021-08-02 06:36:35 +00:00
|
|
|
Destination: &hetznerCloudImage,
|
2021-08-02 01:10:41 +00:00
|
|
|
},
|
|
|
|
&cli.StringSliceFlag{
|
|
|
|
Name: "ssh-keys",
|
|
|
|
Aliases: []string{"s"},
|
|
|
|
Usage: "SSH keys",
|
2021-08-02 06:36:35 +00:00
|
|
|
Destination: &hetznerCloudSSHKeys,
|
2021-08-02 01:10:41 +00:00
|
|
|
},
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "location",
|
|
|
|
Aliases: []string{"l"},
|
|
|
|
Usage: "Server location",
|
|
|
|
Value: "hel1",
|
2021-08-02 06:36:35 +00:00
|
|
|
Destination: &hetznerCloudLocation,
|
2021-08-02 01:10:41 +00:00
|
|
|
},
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "token",
|
|
|
|
Aliases: []string{"T"},
|
|
|
|
Usage: "Hetzner Cloud API token",
|
2021-08-02 12:05:39 +00:00
|
|
|
EnvVars: []string{"HCLOUD_TOKEN"},
|
2021-08-02 06:36:35 +00:00
|
|
|
Destination: &hetznerCloudAPIToken,
|
2021-08-02 01:10:41 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
name := c.Args().First()
|
|
|
|
if name == "" {
|
2021-08-03 11:57:12 +00:00
|
|
|
internal.ShowSubcommandHelpAndError(c, errors.New("no name provided"))
|
2021-08-02 01:10:41 +00:00
|
|
|
}
|
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
if hetznerCloudAPIToken == "" {
|
2021-09-10 22:54:02 +00:00
|
|
|
logrus.Fatal("Hetzner Cloud API token is missing")
|
2021-08-02 12:05:39 +00:00
|
|
|
}
|
|
|
|
|
2021-08-02 01:10:41 +00:00
|
|
|
ctx := context.Background()
|
2021-08-02 06:36:35 +00:00
|
|
|
client := hcloud.NewClient(hcloud.WithToken(hetznerCloudAPIToken))
|
2021-08-02 01:10:41 +00:00
|
|
|
|
2021-09-10 22:54:02 +00:00
|
|
|
logrus.Debugf("successfully created hetzner cloud API client")
|
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-08-02 01:10:41 +00:00
|
|
|
|
|
|
|
serverOpts := hcloud.ServerCreateOpts{
|
|
|
|
Name: name,
|
2021-08-02 06:36:35 +00:00
|
|
|
ServerType: &hcloud.ServerType{Name: hetznerCloudType},
|
|
|
|
Image: &hcloud.Image{Name: hetznerCloudImage},
|
2021-08-02 12:05:39 +00:00
|
|
|
SSHKeys: sshKeys,
|
|
|
|
Location: &hcloud.Location{Name: hetznerCloudLocation},
|
2021-08-02 01:10:41 +00:00
|
|
|
}
|
2021-08-02 12:05:39 +00:00
|
|
|
res, _, err := client.Server.Create(ctx, serverOpts)
|
2021-08-02 01:10:41 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2021-09-10 22:54:02 +00:00
|
|
|
logrus.Debugf("new server '%s' created", name)
|
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
tableColumns := []string{"Name", "IPv4", "Root Password"}
|
|
|
|
table := formatter.CreateTable(tableColumns)
|
2021-09-10 22:54:02 +00:00
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
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})
|
|
|
|
}
|
2021-09-10 22:54:02 +00:00
|
|
|
|
2021-08-02 12:05:39 +00:00
|
|
|
table.Render()
|
|
|
|
|
2021-08-02 01:10:41 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-08-02 13:11:14 +00:00
|
|
|
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.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
Your token can be loaded from the environment using the CAPSUL_TOKEN
|
|
|
|
environment variable or otherwise passing the "--env/-e" 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 {
|
2021-10-20 15:25:46 +00:00
|
|
|
capsulName := c.Args().First()
|
|
|
|
if capsulName == "" {
|
2021-08-03 11:57:12 +00:00
|
|
|
internal.ShowSubcommandHelpAndError(c, errors.New("no name provided"))
|
2021-08-02 13:11:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if capsulAPIToken == "" {
|
2021-09-10 22:54:02 +00:00
|
|
|
logrus.Fatal("Capsul API token is missing")
|
2021-08-02 13:11:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
capsulCreateURL := fmt.Sprintf("https://%s/api/capsul/create", capsulInstance)
|
|
|
|
|
2021-10-20 15:25:46 +00:00
|
|
|
capsulClient := libcapsul.New(capsulCreateURL, capsulAPIToken)
|
|
|
|
resp, err := capsulClient.Create(capsulName, capsulType, capsulImage, capsulSSHKey)
|
2021-08-02 13:11:14 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tableColumns := []string{"Name", "ID"}
|
|
|
|
table := formatter.CreateTable(tableColumns)
|
2021-10-20 15:25:46 +00:00
|
|
|
table.Append([]string{capsulName, resp.ID})
|
2021-08-02 13:11:14 +00:00
|
|
|
table.Render()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-08-02 01:10:41 +00:00
|
|
|
var serverNewCommand = &cli.Command{
|
2021-09-10 13:04:01 +00:00
|
|
|
Name: "new",
|
|
|
|
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.
|
|
|
|
`,
|
|
|
|
ArgsUsage: "<provider>",
|
2021-08-02 01:10:41 +00:00
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
serverNewHetznerCloudCommand,
|
2021-08-02 13:11:14 +00:00
|
|
|
serverNewCapsulCommand,
|
2021-08-02 01:10:41 +00:00
|
|
|
},
|
|
|
|
}
|