refactor: better SSH connection details handling
continuous-integration/drone/push Build is passing Details

This commit is contained in:
decentral1se 2021-10-25 10:42:39 +02:00
parent f9e2d24550
commit 9e0d77d5c6
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
3 changed files with 106 additions and 73 deletions

View File

@ -24,18 +24,16 @@ var recipeNewCommand = &cli.Command{
directory := path.Join(config.APPS_DIR, recipe.Name)
if _, err := os.Stat(directory); !os.IsNotExist(err) {
logrus.Fatalf("'%s' recipe directory already exists?", directory)
return nil
}
url := fmt.Sprintf("%s/example.git", config.REPOS_BASE_URL)
if err := git.Clone(directory, url); err != nil {
return err
logrus.Fatal(err)
}
gitRepo := path.Join(config.APPS_DIR, recipe.Name, ".git")
if err := os.RemoveAll(gitRepo); err != nil {
logrus.Fatal(err)
return nil
}
logrus.Debugf("removed git repo in '%s'", gitRepo)
@ -48,13 +46,11 @@ var recipeNewCommand = &cli.Command{
file, err := os.OpenFile(path, os.O_RDWR, 0755)
if err != nil {
logrus.Fatal(err)
return nil
}
tpl, err := template.ParseFiles(path)
if err != nil {
logrus.Fatal(err)
return nil
}
// TODO: ask for description and probably other things so that the
@ -65,7 +61,6 @@ var recipeNewCommand = &cli.Command{
Description string
}{recipe.Name, "TODO"}); err != nil {
logrus.Fatal(err)
return nil
}
}

View File

@ -8,21 +8,43 @@ import (
"os"
"os/exec"
"os/user"
"path/filepath"
"strings"
"time"
"coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/server"
"coopcloud.tech/abra/pkg/ssh"
"github.com/AlecAivazis/survey/v2"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
dockerClient "github.com/docker/docker/client"
"github.com/sfreiberg/simplessh"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var (
dockerInstallMsg = `
A docker installation cannot be found on %s. This is a required system dependency
for running Co-op Cloud on your server. If you would like, Abra can attempt to install
Docker for you using the upstream non-interactive installation script.
See the following documentation for more:
https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script
N.B Docker doesn't recommend it for production environments but many use it for
such purposes. Docker stable is now installed by default by this script. The
source for this script can be seen here:
https://github.com/docker/docker-install
`
)
var local bool
var localFlag = &cli.BoolFlag{
Name: "local",
@ -68,6 +90,40 @@ var traefikFlag = &cli.BoolFlag{
Destination: &traefik,
}
func cleanUp(domainName string) {
logrus.Warnf("cleaning up context for %s", domainName)
if err := client.DeleteContext(domainName); err != nil {
logrus.Fatal(err)
}
logrus.Warnf("cleaning up server directory for %s", domainName)
if err := os.RemoveAll(filepath.Join(config.ABRA_SERVER_FOLDER, domainName)); err != nil {
logrus.Fatal(err)
}
}
func installDockerLocal(c *cli.Context) error {
fmt.Println(fmt.Sprintf(dockerInstallMsg, "this local server"))
response := false
prompt := &survey.Confirm{
Message: fmt.Sprintf("attempt install docker on local server?"),
}
if err := survey.AskOne(prompt, &response); err != nil {
return err
}
if !response {
logrus.Fatal("exiting as requested")
}
cmd := exec.Command("bash", "-c", "curl -s https://get.docker.com | bash")
if err := internal.RunCmd(cmd); err != nil {
return err
}
return nil
}
func newLocalServer(c *cli.Context, domainName string) error {
if err := createServerDir(domainName); err != nil {
return err
@ -80,7 +136,7 @@ func newLocalServer(c *cli.Context, domainName string) error {
if _, err := exec.LookPath("docker"); err != nil {
if provision {
if err := installDocker(c, cl, domainName); err != nil {
if err := installDockerLocal(c); err != nil {
return err
}
if err := initSwarm(c, cl, domainName); err != nil {
@ -104,21 +160,7 @@ func newLocalServer(c *cli.Context, domainName string) error {
return nil
}
func newContext(c *cli.Context, domainName string) error {
username := c.Args().Get(1)
if username == "" {
systemUser, err := user.Current()
if err != nil {
return err
}
username = systemUser.Username
}
port := c.Args().Get(2)
if port == "" {
port = "22"
}
func newContext(c *cli.Context, domainName, username, port string) error {
store := client.NewDefaultDockerContextStore()
contexts, err := store.Store.List()
if err != nil {
@ -144,48 +186,19 @@ func newContext(c *cli.Context, domainName string) error {
func newClient(c *cli.Context, domainName string) (*dockerClient.Client, error) {
cl, err := client.New(domainName)
if err != nil {
logrus.Warn("cleaning up context due to connection failure")
if err := client.DeleteContext(domainName); err != nil {
return &dockerClient.Client{}, err
}
return &dockerClient.Client{}, err
}
return cl, nil
}
func installDocker(c *cli.Context, cl *dockerClient.Client, domainName string) error {
logrus.Debugf("attempting to construct SSH client for %s", domainName)
client, err := ssh.New(domainName, sshAuth)
if err != nil {
return err
}
defer client.Close()
logrus.Debugf("successfully created SSH client for %s", domainName)
result, err := client.Exec("which docker")
func installDocker(c *cli.Context, cl *dockerClient.Client, sshCl *simplessh.Client, domainName string) error {
result, err := sshCl.Exec("which docker")
if err != nil && string(result) != "" {
return err
}
if string(result) == "" {
fmt.Println(fmt.Sprintf(`
A docker installation cannot be found on %s. This is a required system dependency
for running Co-op Cloud on your server. If you would like, Abra can attempt to install
Docker for you using the upstream non-interactive installation script.
See the following documentation for more:
https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script
N.B Docker doesn't recommend it for production environments but many use it for
such purposes. Docker stable is now installed by default by this script. The
source for this script can be seen here:
https://github.com/docker/docker-install
`, domainName))
fmt.Println(fmt.Sprintf(dockerInstallMsg, domainName))
response := false
prompt := &survey.Confirm{
@ -209,13 +222,13 @@ source for this script can be seen here:
return err
}
logrus.Debugf("running '%s' on %s now with sudo password", cmd, domainName)
_, err := client.ExecSudo(cmd, sudoPass)
_, err := sshCl.ExecSudo(cmd, sudoPass)
if err != nil {
return err
}
} else {
logrus.Debugf("running '%s' on %s now without sudo password", cmd, domainName)
_, err := client.Exec(cmd)
_, err := sshCl.Exec(cmd)
if err != nil {
return err
}
@ -378,11 +391,25 @@ You may omit flags to avoid performing this provisioning logic.
logrus.Fatal(err)
}
username := c.Args().Get(1)
if username == "" {
systemUser, err := user.Current()
if err != nil {
return err
}
username = systemUser.Username
}
port := c.Args().Get(2)
if port == "" {
port = "22"
}
if err := createServerDir(domainName); err != nil {
logrus.Fatal(err)
}
if err := newContext(c, domainName); err != nil {
if err := newContext(c, domainName, username, port); err != nil {
logrus.Fatal(err)
}
@ -392,7 +419,15 @@ You may omit flags to avoid performing this provisioning logic.
}
if provision {
if err := installDocker(c, cl, domainName); err != nil {
logrus.Debugf("attempting to construct SSH client for %s", domainName)
sshCl, err := ssh.New(domainName, sshAuth, username, port)
if err != nil {
logrus.Fatal(err)
}
defer sshCl.Close()
logrus.Debugf("successfully created SSH client for %s", domainName)
if err := installDocker(c, cl, sshCl, domainName); err != nil {
logrus.Fatal(err)
}
if err := initSwarm(c, cl, domainName); err != nil {

View File

@ -19,29 +19,32 @@ type HostConfig struct {
}
// GetHostConfig retrieves a ~/.ssh/config config for a host.
func GetHostConfig(hostname string, hasIdentityFile bool) (HostConfig, error) {
func GetHostConfig(hostname, username, port string, hasIdentityFile bool) (HostConfig, error) {
var hostConfig HostConfig
var host, sshUser, port, idf string
var host, idf string
if host = ssh_config.Get(hostname, "Hostname"); host == "" {
logrus.Debugf("no hostname found in SSH config, assuming %s", hostname)
host = hostname
}
if sshUser = ssh_config.Get(hostname, "User"); sshUser == "" {
systemUser, err := user.Current()
if err != nil {
return hostConfig, err
if username == "" {
if username = ssh_config.Get(hostname, "User"); username == "" {
systemUser, err := user.Current()
if err != nil {
return hostConfig, err
}
logrus.Debugf("no username found in SSH config or passed on command-line, assuming %s", username)
username = systemUser.Username
}
username := systemUser.Username
logrus.Debugf("no username found in SSH config, assuming %s", username)
sshUser = username
}
if port = ssh_config.Get(hostname, "Port"); port == "" {
logrus.Debugf("no port found in SSH config, assuming 22")
port = "22"
if port == "" {
if port = ssh_config.Get(hostname, "Port"); port == "" {
logrus.Debugf("no port found in SSH config or passed on command-line, assuming 22")
port = "22"
}
}
dummyVal := "~/.ssh/identity"
@ -52,7 +55,7 @@ func GetHostConfig(hostname string, hasIdentityFile bool) (HostConfig, error) {
hostConfig.Host = host
hostConfig.IdentityFile = idf
hostConfig.Port = port
hostConfig.User = sshUser
hostConfig.User = username
logrus.Debugf("constructed SSH config %s for %s", hostConfig, hostname)
@ -60,7 +63,7 @@ func GetHostConfig(hostname string, hasIdentityFile bool) (HostConfig, error) {
}
// New creates a new SSH client connection.
func New(domainName, sshAuth string) (*simplessh.Client, error) {
func New(domainName, sshAuth, username, port string) (*simplessh.Client, error) {
var client *simplessh.Client
hasIdentityFile := true
@ -68,7 +71,7 @@ func New(domainName, sshAuth string) (*simplessh.Client, error) {
hasIdentityFile = false
}
hostConfig, err := GetHostConfig(domainName, hasIdentityFile)
hostConfig, err := GetHostConfig(domainName, username, port, hasIdentityFile)
if err != nil {
return client, err
}