Less confusing logging messages, clear "is created" / "already exists" output. Move the majority of logging to debug output to not confuse the situation. Some code cleanups also in there.
202 lines
4.9 KiB
Go
202 lines
4.9 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"coopcloud.tech/abra/cli/internal"
|
|
"coopcloud.tech/abra/pkg/client"
|
|
"coopcloud.tech/abra/pkg/config"
|
|
contextPkg "coopcloud.tech/abra/pkg/context"
|
|
"coopcloud.tech/abra/pkg/dns"
|
|
"coopcloud.tech/abra/pkg/server"
|
|
sshPkg "coopcloud.tech/abra/pkg/ssh"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var local bool
|
|
var localFlag = &cli.BoolFlag{
|
|
Name: "local, l",
|
|
Usage: "Use local server",
|
|
Destination: &local,
|
|
}
|
|
|
|
// cleanUp cleans up the partially created context/client details for a failed
|
|
// "server add" attempt.
|
|
func cleanUp(name string) {
|
|
if name != "default" {
|
|
logrus.Debugf("serverAdd: cleanUp: cleaning up context for %s", name)
|
|
if err := client.DeleteContext(name); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
}
|
|
|
|
serverDir := filepath.Join(config.SERVERS_DIR, name)
|
|
files, err := config.GetAllFilesInDirectory(serverDir)
|
|
if err != nil {
|
|
logrus.Fatalf("serverAdd: cleanUp: unable to list files in %s: %s", serverDir, err)
|
|
}
|
|
|
|
if len(files) > 0 {
|
|
logrus.Debugf("serverAdd: cleanUp: %s is not empty, aborting cleanup", serverDir)
|
|
return
|
|
}
|
|
|
|
if err := os.RemoveAll(serverDir); err != nil {
|
|
logrus.Fatalf("serverAdd: cleanUp: failed to remove %s: %s", serverDir, err)
|
|
}
|
|
}
|
|
|
|
// newContext creates a new internal Docker context for a server. This is how
|
|
// Docker manages SSH connection details. These are stored to disk in
|
|
// ~/.docker. Abra can manage this completely for the user, so it's an
|
|
// implementation detail.
|
|
func newContext(name string) (bool, error) {
|
|
store := contextPkg.NewDefaultDockerContextStore()
|
|
contexts, err := store.Store.List()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
for _, context := range contexts {
|
|
if context.Name == name {
|
|
logrus.Debugf("context for %s already exists", name)
|
|
return false, nil
|
|
}
|
|
}
|
|
|
|
logrus.Debugf("creating context with domain %s", name)
|
|
|
|
if err := client.CreateContext(name); err != nil {
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// createServerDir creates the ~/.abra/servers/... directory for a new server.
|
|
func createServerDir(name string) (bool, error) {
|
|
if err := server.CreateServerDir(name); err != nil {
|
|
if !os.IsExist(err) {
|
|
return false, err
|
|
}
|
|
|
|
logrus.Debugf("server dir for %s already created", name)
|
|
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
var serverAddCommand = cli.Command{
|
|
Name: "add",
|
|
Aliases: []string{"a"},
|
|
Usage: "Add a server to your configuration",
|
|
Description: `
|
|
Add a new server to your configuration so that it can be managed by Abra.
|
|
|
|
Abra relies on the standard SSH command-line and ~/.ssh/config for client
|
|
connection details. You must configure an entry per-host in your ~/.ssh/config
|
|
for each server. For example:
|
|
|
|
Host example.com example
|
|
Hostname example.com
|
|
User exampleUser
|
|
Port 12345
|
|
IdentityFile ~/.ssh/example@somewhere
|
|
|
|
You can then add a server like so:
|
|
|
|
abra server add example.com
|
|
|
|
If "--local" is passed, then Abra assumes that the current local server is
|
|
intended as the target server. This is useful when you want to have your entire
|
|
Co-op Cloud config located on the server itself, and not on your local
|
|
developer machine. The domain is then set to "default".
|
|
|
|
You can also pass "--no-domain-checks/-D" flag to use any arbitrary name
|
|
instead of a real domain. The host will be resolved with the "Hostname" entry
|
|
of your ~/.ssh/config. Checks for a valid online domain will be skipped:
|
|
|
|
abra server add -D example
|
|
`,
|
|
Flags: []cli.Flag{
|
|
internal.DebugFlag,
|
|
internal.NoInputFlag,
|
|
internal.NoDomainChecksFlag,
|
|
localFlag,
|
|
},
|
|
Before: internal.SubCommandBefore,
|
|
ArgsUsage: "<name>",
|
|
Action: func(c *cli.Context) error {
|
|
if len(c.Args()) > 0 && local || !internal.ValidateSubCmdFlags(c) {
|
|
err := errors.New("cannot use <name> and --local together")
|
|
internal.ShowSubcommandHelpAndError(c, err)
|
|
}
|
|
|
|
var name string
|
|
if local {
|
|
name = "default"
|
|
} else {
|
|
name = internal.ValidateDomain(c)
|
|
}
|
|
|
|
if local {
|
|
created, err := createServerDir(name)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
logrus.Debugf("attempting to create client for %s", name)
|
|
|
|
if _, err := client.New(name); err != nil {
|
|
cleanUp(name)
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
if created {
|
|
logrus.Info("local server successfully added")
|
|
} else {
|
|
logrus.Warn("local server already exists")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
if !internal.NoDomainChecks {
|
|
if _, err := dns.EnsureIPv4(name); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
}
|
|
|
|
_, err := createServerDir(name)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
created, err := newContext(name)
|
|
if err != nil {
|
|
cleanUp(name)
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
logrus.Debugf("attempting to create client for %s", name)
|
|
if _, err := client.New(name); err != nil {
|
|
cleanUp(name)
|
|
logrus.Debugf("failed to construct client for %s, saw %s", name, err.Error())
|
|
logrus.Fatal(sshPkg.Fatal(name, err))
|
|
}
|
|
|
|
if created {
|
|
logrus.Infof("%s successfully added", name)
|
|
} else {
|
|
logrus.Warnf("%s already exists", name)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|