fix: working provisioning post chaos testing
continuous-integration/drone/push Build is passing Details

This commit is contained in:
decentral1se 2021-10-25 10:06:16 +02:00
parent a7970132c2
commit 8772217f41
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
3 changed files with 124 additions and 84 deletions

View File

@ -19,7 +19,6 @@ import (
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/sfreiberg/simplessh"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -155,9 +154,23 @@ func newClient(c *cli.Context, domainName string) (*dockerClient.Client, error)
} }
func installDocker(c *cli.Context, cl *dockerClient.Client, domainName string) error { func installDocker(c *cli.Context, cl *dockerClient.Client, domainName string) error {
if _, err := cl.Info(c.Context); err != nil { logrus.Debugf("attempting to construct SSH client for %s", domainName)
if strings.Contains(err.Error(), "command not found") {
fmt.Println(fmt.Sprintf(` 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")
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 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 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. Docker for you using the upstream non-interactive installation script.
@ -174,81 +187,43 @@ source for this script can be seen here:
`, domainName)) `, domainName))
response := false response := false
prompt := &survey.Confirm{ prompt := &survey.Confirm{
Message: fmt.Sprintf("attempt install docker on %s?", domainName), Message: fmt.Sprintf("attempt install docker on %s?", domainName),
}
if err := survey.AskOne(prompt, &response); err != nil {
return err
}
if !response {
logrus.Fatal("exiting as requested")
}
cmd := "curl -s https://get.docker.com | bash"
var sudoPass string
if askSudoPass {
prompt := &survey.Password{
Message: "sudo password?",
} }
if err := survey.AskOne(prompt, &response); err != nil { if err := survey.AskOne(prompt, &sudoPass); err != nil {
return err return err
} }
if !response { logrus.Debugf("running '%s' on %s now with sudo password", cmd, domainName)
logrus.Fatal("exiting as requested") _, err := client.ExecSudo(cmd, sudoPass)
}
hasIdentityFile := true
if sshAuth == "password" {
hasIdentityFile = false
}
hostConfig, err := ssh.GetHostConfig(domainName, hasIdentityFile)
if err != nil { if err != nil {
return err return err
} }
} else {
var client *simplessh.Client logrus.Debugf("running '%s' on %s now without sudo password", cmd, domainName)
if sshAuth == "identity-file" { _, err := client.Exec(cmd)
var err error if err != nil {
client, err = simplessh.ConnectWithAgent(hostConfig.Host, hostConfig.User) return err
if err != nil {
return err
}
} else {
password := ""
prompt := &survey.Password{
Message: "SSH password?",
}
if err := survey.AskOne(prompt, &password); err != nil {
return err
}
var err error
client, err = simplessh.ConnectWithPassword(hostConfig.Host, hostConfig.User, password)
if err != nil {
return err
}
} }
defer client.Close()
logrus.Debugf("successfully created SSH client for %s", domainName)
cmd := "curl -s https://get.docker.com | bash"
var sudoPass string
if askSudoPass {
prompt := &survey.Password{
Message: "sudo password?",
}
if err := survey.AskOne(prompt, &sudoPass); err != nil {
return err
}
logrus.Debugf("running '%s' on %s now with sudo password", cmd, domainName)
_, err := client.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)
if err != nil {
return err
}
}
logrus.Infof("docker has successfully been installed on %s", domainName)
return nil
} }
} }
logrus.Infof("docker is installed on %s", domainName)
return nil return nil
} }
@ -381,12 +356,7 @@ You may omit flags to avoid performing this provisioning logic.
}, },
ArgsUsage: "<domain> [<user>] [<port>]", ArgsUsage: "<domain> [<user>] [<port>]",
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
if c.Args().Len() == 2 && !local { if c.Args().Len() > 0 && local {
err := errors.New("missing arguments <domain> or '--local'")
internal.ShowSubcommandHelpAndError(c, err)
}
if c.Args().Get(2) != "" && local {
err := errors.New("cannot use '<domain>' and '--local' together") err := errors.New("cannot use '<domain>' and '--local' together")
internal.ShowSubcommandHelpAndError(c, err) internal.ShowSubcommandHelpAndError(c, err)
} }

View File

@ -84,6 +84,18 @@ Your new Hetzner Cloud VPS has successfully been created! Here are the details:
VPS IP address: %s VPS IP address: %s
VPS Root Password: %s VPS Root Password: %s
Here is what your SSH configuration (~/.ssh/config) might look like:
Host %s.example.com
Hostname %s
User root
Port 22
IdentityFile ~/.ssh/<your-ssh-private-key>
Remember, your "Host" value must be a valid publicly accessible domain name as
Abra uses this domain to identity servers. If you specified "--ssh-auth
password" then you may skip the IdentityFile stanza.
You can access this new VPS via SSH using the following command: You can access this new VPS via SSH using the following command:
ssh root@%s ssh root@%s
@ -92,7 +104,11 @@ 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 ("abra not list this server)! You will need to assign a domain name record ("abra
record new") and add the server to your Abra configuration ("abra server add") 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. to have a working server that you can deploy Co-op Cloud apps to.
`, internal.HetznerCloudName, ip, rootPassword, ip)) `,
internal.HetznerCloudName, ip, rootPassword,
internal.HetznerCloudName, ip,
ip,
))
return nil return nil
} }

View File

@ -2,8 +2,12 @@ package ssh
import ( import (
"fmt" "fmt"
"os/user"
"github.com/AlecAivazis/survey/v2"
"github.com/kevinburke/ssh_config" "github.com/kevinburke/ssh_config"
"github.com/sfreiberg/simplessh"
"github.com/sirupsen/logrus"
) )
// HostConfig is a SSH host config. // HostConfig is a SSH host config.
@ -18,28 +22,78 @@ type HostConfig struct {
func GetHostConfig(hostname string, hasIdentityFile bool) (HostConfig, error) { func GetHostConfig(hostname string, hasIdentityFile bool) (HostConfig, error) {
var hostConfig HostConfig var hostConfig HostConfig
var host, user, port, idf string var host, sshUser, port, idf string
if host = ssh_config.Get(hostname, "Hostname"); host == "" { if host = ssh_config.Get(hostname, "Hostname"); host == "" {
return hostConfig, fmt.Errorf("SSH hostname missing for %s from SSH config", hostname) logrus.Debugf("no hostname found in SSH config, assuming %s", hostname)
host = hostname
} }
if user = ssh_config.Get(hostname, "User"); user == "" { if sshUser = ssh_config.Get(hostname, "User"); sshUser == "" {
return hostConfig, fmt.Errorf("SSH user missing for %s from SSH config", hostname) systemUser, err := user.Current()
if err != nil {
return hostConfig, err
}
username := systemUser.Username
logrus.Debugf("no username found in SSH config, assuming %s", username)
sshUser = username
} }
if port = ssh_config.Get(hostname, "Port"); port == "" { if port = ssh_config.Get(hostname, "Port"); port == "" {
return hostConfig, fmt.Errorf("SSH port missing for %s from SSH config", hostname) logrus.Debugf("no port found in SSH config, assuming 22")
port = "22"
} }
if idf = ssh_config.Get(hostname, "IdentityFile"); idf == "" && hasIdentityFile { dummyVal := "~/.ssh/identity"
if idf = ssh_config.Get(hostname, "IdentityFile"); (idf == dummyVal || idf == "") && hasIdentityFile {
return hostConfig, fmt.Errorf("SSH identity file missing for %s from SSH config", hostname) return hostConfig, fmt.Errorf("SSH identity file missing for %s from SSH config", hostname)
} }
hostConfig.Host = host hostConfig.Host = host
hostConfig.IdentityFile = idf hostConfig.IdentityFile = idf
hostConfig.Port = port hostConfig.Port = port
hostConfig.User = user hostConfig.User = sshUser
logrus.Debugf("constructed SSH config %s for %s", hostConfig, hostname)
return hostConfig, nil return hostConfig, nil
} }
// New creates a new SSH client connection.
func New(domainName, sshAuth string) (*simplessh.Client, error) {
var client *simplessh.Client
hasIdentityFile := true
if sshAuth == "password" {
hasIdentityFile = false
}
hostConfig, err := GetHostConfig(domainName, hasIdentityFile)
if err != nil {
return client, err
}
if sshAuth == "identity-file" {
var err error
client, err = simplessh.ConnectWithAgent(hostConfig.Host, hostConfig.User)
if err != nil {
return client, err
}
} else {
password := ""
prompt := &survey.Password{
Message: "SSH password?",
}
if err := survey.AskOne(prompt, &password); err != nil {
return client, err
}
var err error
client, err = simplessh.ConnectWithPassword(hostConfig.Host, hostConfig.User, password)
if err != nil {
return client, err
}
}
return client, nil
}