fix: working provisioning post chaos testing
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
a7970132c2
commit
8772217f41
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue