Skip to content

Commit

Permalink
#54 Refactor the structure of the packages
Browse files Browse the repository at this point in the history
It might not be the ideal now, but better isolation then it was before. Again iterative way of doing improvements.
  • Loading branch information
zshamrock committed Apr 29, 2018
1 parent 79708b6 commit ba39d2d
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 90 deletions.
5 changes: 3 additions & 2 deletions commands.go → cli_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

"github.com/zshamrock/vmx/command"
"github.com/zshamrock/vmx/config"
"gopkg.in/urfave/cli.v1"
)

Expand Down Expand Up @@ -44,9 +45,9 @@ var Commands = []cli.Command{
BashComplete: func(c *cli.Context) {
var names []string
if c.NArg() == 0 || (c.NArg() == 1 && command.ContainsFollow(c)) {
names = command.GetHostNames()
names = config.GetHostNames()
} else {
names = command.GetCommandNames()
names = config.GetCommandNames()
}
for _, name := range names {
fmt.Println(name)
Expand Down
6 changes: 3 additions & 3 deletions command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ func TestGetCommand(t *testing.T) {
context := cli.NewContext(app, &flags, nil)
command, extraArgs := getCommand(context, true)
if !command.IsAdHoc() {
t.Errorf("Command name should be ad-hoc, but got %s", command.name)
t.Errorf("Command name should be ad-hoc, but got %s", command.Name)
}
if command.command != commandText {
t.Errorf("Command should be %s, but got %s", commandText, command.command)
if command.Command != commandText {
t.Errorf("Command should be %s, but got %s", commandText, command.Command)
}
if extraArgs != "" {
t.Errorf("Extra args should be empty, but got %s", extraArgs)
Expand Down
8 changes: 5 additions & 3 deletions command/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ package command
import (
"fmt"

"github.com/zshamrock/vmx/config"
"gopkg.in/urfave/cli.v1"
)

// CmdList lists available custom command
func CmdList(c *cli.Context) {
CheckUpdate(c)
names := GetCommandNames()
names := config.GetCommandNames()
commands := config.GetCommands()
for _, name := range names {
fmt.Print(name)
if commands[name].requiresConfirmation {
fmt.Printf(" (%s)\n", commandNameConfirmationSuffix)
if commands[name].RequiresConfirmation {
fmt.Printf(" (%s)\n", config.CommandNameConfirmationSuffix)
} else {
fmt.Println("")
}
Expand Down
71 changes: 35 additions & 36 deletions command/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,59 @@ import (

"github.com/kevinburke/ssh_config"
"github.com/zshamrock/vmx/config"
"github.com/zshamrock/vmx/core"
"gopkg.in/urfave/cli.v1"
)

const (
optionalFollowArgsIndex = 0
hostsGroupArgsIndex = 0
commandNameArgsIndex = 1
hostsGroupChildrenSuffix = ":children"
allHostsGroup = "all"
FollowArgName = "follow"
optionalFollowArgsIndex = 0
hostsGroupArgsIndex = 0
commandNameArgsIndex = 1
FollowArgName = "follow"
)

type execOutput struct {
name, host string
output string
}

// CmdRun runs custom command
func CmdRun(c *cli.Context) {
CheckUpdate(c)
follow := ContainsFollow(c)
command, extraArgs := getCommand(c, follow)
hosts := getHosts(c, follow)
var confirmation string
if command.requiresConfirmation {
fmt.Printf("Confirm to run \"%s\" command on %v - yes/no or y/n: ", command.name, hosts)
if command.RequiresConfirmation {
fmt.Printf("Confirm to run \"%s\" command on %v - yes/no or y/n: ", command.Name, hosts)
fmt.Scanln(&confirmation)
}
confirmation = strings.ToLower(confirmation)
if command.requiresConfirmation && confirmation != "yes" && confirmation != "y" {
if command.RequiresConfirmation && confirmation != "yes" && confirmation != "y" {
return
}
cmd := command.command
if command.workingDir != "" {
cmd = strings.TrimSpace(fmt.Sprintf("cd %s && %s %s", command.workingDir, cmd, extraArgs))
cmd := command.Command
if command.WorkingDir != "" {
cmd = strings.TrimSpace(fmt.Sprintf("cd %s && %s %s", command.WorkingDir, cmd, extraArgs))
}
fmt.Printf("Running command: %s from %s on %v\n", command.command, command.workingDir, hosts)
fmt.Printf("Running command: %s from %s on %v\n", command.Command, command.WorkingDir, hosts)
sshConfig := readSSHConfig(config.DefaultConfig)
ch := make(chan ExecOutput, len(hosts))
ch := make(chan execOutput, len(hosts))
for _, host := range hosts {
if command.workingDir == "" && !strings.Contains(cmd, "cd ") {
if command.WorkingDir == "" && !strings.Contains(cmd, "cd ") {
// Try to extend the command with the working dir from the defaults config, unless the command already has
// have one, which takes the precedence. Also avoid to extend the command with the working dir from the
// defaults config, if the command has "cd " in it, assuming user configured the working dir explicitly.
defaults := getDefaults(host)
workingDir, ok := defaults[SectionWorkingDirKeyName]
defaults := config.GetDefaults(host)
workingDir, ok := defaults[config.SectionWorkingDirKeyName]
if ok {
fmt.Printf("Using working dir %s from the defaults config\n", workingDir)
cmd = fmt.Sprintf("cd %s && %s", workingDir, cmd)
}
}
go SSH(sshConfig, host, cmd, follow, ch)
go ssh(sshConfig, host, cmd, follow, ch)
}
outputs := make([]ExecOutput, 0, len(hosts))
outputs := make([]execOutput, 0, len(hosts))
for i := 0; i < len(hosts); i++ {
outputs = append(outputs, <-ch)
}
Expand All @@ -70,16 +74,21 @@ func CmdRun(c *cli.Context) {
fmt.Println(output.output)
}
}
func getCommand(c *cli.Context, follow bool) (Command, string) {
func getCommand(c *cli.Context, follow bool) (core.Command, string) {
args := c.Args()
actualCommandNameArgsIndex := getActualArgsIndex(commandNameArgsIndex, follow)
commandName := strings.TrimSpace(args.Get(actualCommandNameArgsIndex))
command, ok := commands[commandName]
command, ok := config.GetCommands()[commandName]
if !ok {
adhocCommand := strings.Join(args[actualCommandNameArgsIndex:], " ")
fmt.Printf("%s: custom command \"%s\" is not defined, interpret it as the ad-hoc command: %s\n",
c.App.Name, commandName, adhocCommand)
command = Command{adHocCommandName, adhocCommand, "", false}
command = core.Command{
Name: core.AdHocCommandName,
Command: adhocCommand,
WorkingDir: "",
RequiresConfirmation: false,
}
}
extraArgs := ""
if ok && c.NArg() > 2 {
Expand Down Expand Up @@ -113,7 +122,8 @@ func getHosts(c *cli.Context, follow bool) []string {
}

func getHostsByGroup(c *cli.Context, hostsGroup string) []string {
if hostsGroup == allHostsGroup {
hostsGroups := config.GetHostsGroups()
if hostsGroup == config.AllHostsGroup {
allHosts := make([]string, 0, len(hostsGroups))
for _, hosts := range hostsGroups {
for _, host := range hosts {
Expand All @@ -125,11 +135,11 @@ func getHostsByGroup(c *cli.Context, hostsGroup string) []string {
hosts, ok := hostsGroups[hostsGroup]
if !ok {
// First then try whether host:children exists
hosts, ok = hostsGroups[hostsGroup+hostsGroupChildrenSuffix]
hosts, ok = hostsGroups[hostsGroup+config.HostsGroupChildrenSuffix]
if ok {
children := make([]string, 0, len(hosts))
for _, group := range hosts {
_, ok = hostsGroups[group+hostsGroupChildrenSuffix]
_, ok = hostsGroups[group+config.HostsGroupChildrenSuffix]
if ok {
children = append(children, getHostsByGroup(c, group)...)
} else {
Expand All @@ -146,17 +156,6 @@ func getHostsByGroup(c *cli.Context, hostsGroup string) []string {
return hosts
}

func getDefaults(host string) map[string]string {
values := defaults[host]
if values == nil {
values = defaults[allHostsGroup]
}
if values == nil {
return map[string]string{}
}
return values
}

func readSSHConfig(cfg config.VMXConfig) *ssh_config.Config {
sshConfigFilePath := filepath.Join(cfg.SSHConfigDir, "config")
data, err := ioutil.ReadFile(sshConfigFilePath)
Expand Down
18 changes: 9 additions & 9 deletions command/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"strings"

"github.com/kevinburke/ssh_config"
"golang.org/x/crypto/ssh"
cryptoSSH "golang.org/x/crypto/ssh"
)

const (
Expand All @@ -19,8 +19,8 @@ const (
ignoredIdentitySshFile = "~/.ssh/identity"
)

// SSH implements scp connection to the remote instance
func SSH(sshConfig *ssh_config.Config, host, command string, follow bool, ch chan ExecOutput) {
// ssh implements scp connection to the remote instance
func ssh(sshConfig *ssh_config.Config, host, command string, follow bool, ch chan execOutput) {
fmt.Printf("Running command: %s on host %s\n", command, host)
user, _ := sshConfig.Get(host, SshConfigUserKey)
hostname, _ := sshConfig.Get(host, SshConfigHostnameKey)
Expand All @@ -32,14 +32,14 @@ func SSH(sshConfig *ssh_config.Config, host, command string, follow bool, ch cha
identityFilePath = os.ExpandEnv(strings.Replace(identityFile, "~", "${HOME}", -1))
}
pk, _ := ioutil.ReadFile(identityFilePath)
signer, _ := ssh.ParsePrivateKey([]byte(pk))
config := &ssh.ClientConfig{
signer, _ := cryptoSSH.ParsePrivateKey([]byte(pk))
config := &cryptoSSH.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
Auth: []cryptoSSH.AuthMethod{
cryptoSSH.PublicKeys(signer),
},
}
client, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", hostname), config)
client, err := cryptoSSH.Dial("tcp", fmt.Sprintf("%s:22", hostname), config)
if err != nil {
log.Panicf("Failed to dial to the host %s: %v\n", host, err.Error())
}
Expand All @@ -60,7 +60,7 @@ func SSH(sshConfig *ssh_config.Config, host, command string, follow bool, ch cha
log.Panicf("Failed to run command \"%s\" on the host %s: %v\n", command, host, err.Error())
}
fmt.Fprintf(&output, "Command completed on the host %s\n", host)
ch <- ExecOutput{
ch <- execOutput{
command,
host,
output.String(),
Expand Down
4 changes: 4 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const (
defaultVmxHome = "${HOME}/.vmx"
vmxSSHConfigHomeEnvVar = "VMX_SSH_CONFIG_HOME"
defaultSSHConfigHome = "${HOME}/.ssh"

CommandNameConfirmationSuffix = "!"
HostsGroupChildrenSuffix = ":children"
AllHostsGroup = "all"
)

type VMXConfig struct {
Expand Down
Loading

0 comments on commit ba39d2d

Please sign in to comment.