diff --git a/provisioner/guest_commands.go b/provisioner/guest_commands.go new file mode 100644 index 000000000..4a65312f9 --- /dev/null +++ b/provisioner/guest_commands.go @@ -0,0 +1,72 @@ +package provisioner + +import ( + "fmt" + "strings" +) + +const UnixOSType = "unix" +const WindowsOSType = "windows" +const DefaultOSType = UnixOSType + +type guestOSTypeCommand struct { + chmod string + mkdir string + removeDir string +} + +var guestOSTypeCommands = map[string]guestOSTypeCommand{ + UnixOSType: guestOSTypeCommand{ + chmod: "chmod %s '%s'", + mkdir: "mkdir -p '%s'", + removeDir: "rm -rf '%s'", + }, + WindowsOSType: guestOSTypeCommand{ + chmod: "echo 'skipping chmod %s %s'", // no-op + mkdir: "New-Item -ItemType directory -Force -ErrorAction SilentlyContinue -Path %s", + removeDir: "rm %s -recurse -force", + }, +} + +type GuestCommands struct { + GuestOSType string + Sudo bool +} + +func NewGuestCommands(osType string, sudo bool) (*GuestCommands, error) { + _, ok := guestOSTypeCommands[osType] + if !ok { + return nil, fmt.Errorf("Invalid osType: \"%s\"", osType) + } + return &GuestCommands{GuestOSType: osType, Sudo: sudo}, nil +} + +func (g *GuestCommands) Chmod(path string, mode string) string { + return g.sudo(fmt.Sprintf(g.commands().chmod, mode, g.escapePath(path))) +} + +func (g *GuestCommands) CreateDir(path string) string { + return g.sudo(fmt.Sprintf(g.commands().mkdir, g.escapePath(path))) +} + +func (g *GuestCommands) RemoveDir(path string) string { + return g.sudo(fmt.Sprintf(g.commands().removeDir, g.escapePath(path))) +} + +func (g *GuestCommands) commands() guestOSTypeCommand { + return guestOSTypeCommands[g.GuestOSType] +} + +func (g *GuestCommands) escapePath(path string) string { + if g.GuestOSType == WindowsOSType { + return strings.Replace(path, " ", "` ", -1) + } + return path +} + +func (g *GuestCommands) sudo(cmd string) string { + if g.GuestOSType == UnixOSType && g.Sudo { + return "sudo " + cmd + } + return cmd +} \ No newline at end of file diff --git a/provisioner/guest_commands_test.go b/provisioner/guest_commands_test.go new file mode 100644 index 000000000..d07c4bd44 --- /dev/null +++ b/provisioner/guest_commands_test.go @@ -0,0 +1,120 @@ +package provisioner + +import ( + "testing" +) + +func TestNewGuestCommands(t *testing.T) { + _, err := NewGuestCommands("Amiga", true) + if err == nil { + t.Fatalf("Should have returned an err for unsupported OS type") + } +} + +func TestCreateDir(t *testing.T) { + // *nix OS + guestCmd, err := NewGuestCommands(UnixOSType, false) + if err != nil { + t.Fatalf("Failed to create new GuestCommands for OS: %s", UnixOSType) + } + cmd := guestCmd.CreateDir("/tmp/tempdir") + if cmd != "mkdir -p '/tmp/tempdir'" { + t.Fatalf("Unexpected Unix create dir cmd: %s", cmd) + } + + // *nix OS w/sudo + guestCmd, err = NewGuestCommands(UnixOSType, true) + if err != nil { + t.Fatalf("Failed to create new sudo GuestCommands for OS: %s", UnixOSType) + } + cmd = guestCmd.CreateDir("/tmp/tempdir") + if cmd != "sudo mkdir -p '/tmp/tempdir'" { + t.Fatalf("Unexpected Unix sudo create dir cmd: %s", cmd) + } + + // Windows OS + guestCmd, err = NewGuestCommands(WindowsOSType, false) + if err != nil { + t.Fatalf("Failed to create new GuestCommands for OS: %s", WindowsOSType) + } + cmd = guestCmd.CreateDir("C:\\Windows\\Temp\\tempdir") + if cmd != "New-Item -ItemType directory -Force -ErrorAction SilentlyContinue -Path C:\\Windows\\Temp\\tempdir" { + t.Fatalf("Unexpected Windows create dir cmd: %s", cmd) + } + + // Windows OS w/ space in path + cmd = guestCmd.CreateDir("C:\\Windows\\Temp\\temp dir") + if cmd != "New-Item -ItemType directory -Force -ErrorAction SilentlyContinue -Path C:\\Windows\\Temp\\temp` dir" { + t.Fatalf("Unexpected Windows create dir cmd: %s", cmd) + } +} + +func TestChmod(t *testing.T) { + // *nix + guestCmd, err := NewGuestCommands(UnixOSType, false) + if err != nil { + t.Fatalf("Failed to create new GuestCommands for OS: %s", UnixOSType) + } + cmd := guestCmd.Chmod("/usr/local/bin/script.sh", "0666") + if cmd != "chmod 0666 '/usr/local/bin/script.sh'" { + t.Fatalf("Unexpected Unix chmod 0666 cmd: %s", cmd) + } + + // sudo *nix + guestCmd, err = NewGuestCommands(UnixOSType, true) + if err != nil { + t.Fatalf("Failed to create new sudo GuestCommands for OS: %s", UnixOSType) + } + cmd = guestCmd.Chmod("/usr/local/bin/script.sh", "+x") + if cmd != "sudo chmod +x '/usr/local/bin/script.sh'" { + t.Fatalf("Unexpected Unix chmod +x cmd: %s", cmd) + } + + // Windows + guestCmd, err = NewGuestCommands(WindowsOSType, false) + if err != nil { + t.Fatalf("Failed to create new GuestCommands for OS: %s", WindowsOSType) + } + cmd = guestCmd.Chmod("C:\\Program Files\\SomeApp\\someapp.exe", "+x") + if cmd != "echo 'skipping chmod +x C:\\Program` Files\\SomeApp\\someapp.exe'" { + t.Fatalf("Unexpected Windows chmod +x cmd: %s", cmd) + } +} + +func TestRemoveDir(t *testing.T) { + // *nix + guestCmd, err := NewGuestCommands(UnixOSType, false) + if err != nil { + t.Fatalf("Failed to create new GuestCommands for OS: %s", UnixOSType) + } + cmd := guestCmd.RemoveDir("/tmp/somedir") + if cmd != "rm -rf '/tmp/somedir'" { + t.Fatalf("Unexpected Unix remove dir cmd: %s", cmd) + } + + // sudo *nix + guestCmd, err = NewGuestCommands(UnixOSType, true) + if err != nil { + t.Fatalf("Failed to create new sudo GuestCommands for OS: %s", UnixOSType) + } + cmd = guestCmd.RemoveDir("/tmp/somedir") + if cmd != "sudo rm -rf '/tmp/somedir'" { + t.Fatalf("Unexpected Unix sudo remove dir cmd: %s", cmd) + } + + // Windows OS + guestCmd, err = NewGuestCommands(WindowsOSType, false) + if err != nil { + t.Fatalf("Failed to create new GuestCommands for OS: %s", WindowsOSType) + } + cmd = guestCmd.RemoveDir("C:\\Temp\\SomeDir") + if cmd != "rm C:\\Temp\\SomeDir -recurse -force" { + t.Fatalf("Unexpected Windows remove dir cmd: %s", cmd) + } + + // Windows OS w/ space in path + cmd = guestCmd.RemoveDir("C:\\Temp\\Some Dir") + if cmd != "rm C:\\Temp\\Some` Dir -recurse -force" { + t.Fatalf("Unexpected Windows remove dir cmd: %s", cmd) + } +} \ No newline at end of file