-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package vagrant | ||
|
||
// GlobalStatusCommand specifies options and output from vagrant global-status | ||
type GlobalStatusCommand struct { | ||
BaseCommand | ||
GlobalStatusResponse | ||
|
||
// Prune will remove invalid entries. | ||
Prune bool | ||
} | ||
|
||
// GlobalStatus will return the status of all vagrant machines regardless of | ||
// directory. After setting options as appropriate, you must call Run() or | ||
// Start() followed by Wait() to execute. Output will be in Status and any | ||
// error will be in Error. | ||
func (client *VagrantClient) GlobalStatus() *GlobalStatusCommand { | ||
return &GlobalStatusCommand{ | ||
BaseCommand: newBaseCommand(client), | ||
GlobalStatusResponse: newGlobalStatusResponse(), | ||
} | ||
} | ||
|
||
func (cmd *GlobalStatusCommand) buildArguments() []string { | ||
args := []string{} | ||
if cmd.Prune { | ||
args = append(args, "--prune") | ||
} | ||
return args | ||
} | ||
|
||
func (cmd *GlobalStatusCommand) init() error { | ||
args := cmd.buildArguments() | ||
return cmd.BaseCommand.init(&cmd.GlobalStatusResponse, "global-status", args...) | ||
} | ||
|
||
// Run the command | ||
func (cmd *GlobalStatusCommand) Run() error { | ||
if err := cmd.Start(); err != nil { | ||
return err | ||
} | ||
return cmd.Wait() | ||
} | ||
|
||
// Start the command. You must call Wait() to complete execution. | ||
func (cmd *GlobalStatusCommand) Start() error { | ||
if err := cmd.init(); err != nil { | ||
return err | ||
} | ||
return cmd.BaseCommand.Start() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package vagrant | ||
|
||
import ( | ||
"strings" | ||
) | ||
|
||
// GlobalStatus has status information about a single Vagrant VM | ||
type GlobalStatus struct { | ||
// Id of the vagrant vm | ||
Id string | ||
|
||
// Name of the vagrant vm | ||
Name string | ||
|
||
// Provider of the vagrant vm | ||
Provider string | ||
|
||
// The State of the vagrant vm | ||
State string | ||
|
||
// Directory where the vagrant vm was created | ||
Directory string | ||
|
||
// AdditionalInfo has data which may be provided by vagrant in the future as | ||
// a map of string keys and values. | ||
AdditionalInfo map[string]string | ||
} | ||
|
||
func (gs *GlobalStatus) moveInfoToProperties() { | ||
if id, ok := gs.AdditionalInfo["id"]; ok { | ||
delete(gs.AdditionalInfo, "id") | ||
gs.Id = id | ||
} | ||
if name, ok := gs.AdditionalInfo["name"]; ok { | ||
delete(gs.AdditionalInfo, "name") | ||
gs.Name = name | ||
} | ||
if provider, ok := gs.AdditionalInfo["provider"]; ok { | ||
delete(gs.AdditionalInfo, "provider") | ||
gs.Provider = provider | ||
} | ||
if state, ok := gs.AdditionalInfo["state"]; ok { | ||
delete(gs.AdditionalInfo, "state") | ||
gs.State = state | ||
} | ||
if directory, ok := gs.AdditionalInfo["directory"]; ok { | ||
delete(gs.AdditionalInfo, "directory") | ||
gs.Directory = directory | ||
} | ||
} | ||
|
||
// GlobalStatusResponse has the output from vagrant global-status | ||
type GlobalStatusResponse struct { | ||
ErrorResponse | ||
|
||
// Status per Vagrant VM. Keys are vagrant vm ID's (ex: 1a2b3c4d) and values | ||
// are GlobalStatus objects. | ||
Status map[string]*GlobalStatus | ||
|
||
hasKeys bool | ||
keys []string | ||
currentKey int | ||
currentStatus *GlobalStatus | ||
} | ||
|
||
func newGlobalStatusResponse() GlobalStatusResponse { | ||
return GlobalStatusResponse{ | ||
Status: make(map[string]*GlobalStatus), | ||
} | ||
} | ||
|
||
func (resp *GlobalStatusResponse) handleOutput(target, key string, message []string) { | ||
// Only interested in the following output: | ||
// * target: _, key: ui, message: [info, X] | ||
if key == "ui" && len(message) > 1 && message[0] == "info" { | ||
if len(message[1]) > 0 && (strings.Contains(message[1], "\n") || strings.Trim(message[1], "-") == "") { | ||
// There's a line of all -'s that separates the keys from the statuses, | ||
// and the last line contains a paragraph of text with newlines. | ||
// Ignore both. | ||
return | ||
} | ||
|
||
if resp.hasKeys { | ||
if message[1] == "" { | ||
// we're done loading the status for a machine | ||
resp.currentStatus.moveInfoToProperties() | ||
resp.Status[resp.currentStatus.Id] = resp.currentStatus | ||
resp.currentStatus = nil | ||
resp.currentKey = 0 | ||
return | ||
} | ||
if resp.currentKey >= len(resp.keys) { | ||
// more data than there are keys? | ||
return | ||
} | ||
|
||
if resp.currentStatus == nil { | ||
resp.currentStatus = &GlobalStatus{AdditionalInfo: make(map[string]string)} | ||
} | ||
resp.currentStatus.AdditionalInfo[resp.keys[resp.currentKey]] = message[1] | ||
resp.currentKey++ | ||
} else { | ||
if message[1] == "" { | ||
// we're done loading all the keys | ||
resp.hasKeys = true | ||
return | ||
} | ||
resp.keys = append(resp.keys, message[1]) | ||
} | ||
} else { | ||
resp.ErrorResponse.handleOutput(target, key, message) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package vagrant | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestGlobalStatusResponse_handleOutput(t *testing.T) { | ||
parser := MockOutputParser{} | ||
data := newGlobalStatusResponse() | ||
parser.Run(successfulOutput["global-status"], &data) | ||
|
||
if data.Error != nil { | ||
t.Errorf("Successful vagrant global-status should not have set an error: %v", data.Error) | ||
} | ||
|
||
if len(data.Status) != 3 { | ||
t.Fatalf("There should have been 3 statuses; instead there were %v", len(data.Status)) | ||
} | ||
|
||
status, ok := data.Status["dc1c471"] | ||
if !ok { | ||
t.Fatalf("There should have been a status for 'dc1c471'; instead, keys were %v", | ||
reflect.ValueOf(data.Status).MapKeys()) | ||
} | ||
if status.Id != "dc1c471" { | ||
t.Errorf("Expected Id of 'dc1c471'; got %v", status.Id) | ||
} | ||
if status.Name != "box-2" { | ||
t.Errorf("Expected Name of 'box-2'; got %v", status.Name) | ||
} | ||
if status.Provider != "virtualbox" { | ||
t.Errorf("Expected Provider of 'virtualbox'; got %v", status.Provider) | ||
} | ||
if status.State != "running" { | ||
t.Errorf("Expected State of 'running'; got %v", status.State) | ||
} | ||
if status.Directory != "/path/to/box/2" { | ||
t.Errorf("Expected Directory of '/path/to/box/2'; got %v", status.Directory) | ||
} | ||
if len(status.AdditionalInfo) != 0 { | ||
t.Errorf("Expected len(AdditionalInfo) to be 0; got %v with keys %v", | ||
len(status.AdditionalInfo), | ||
reflect.ValueOf(status.AdditionalInfo).MapKeys()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package vagrant | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func init() { | ||
successfulOutput["global-status"] = ` | ||
1537232052,,ui,info,id | ||
1537232052,,ui,info,name | ||
1537232052,,ui,info,provider | ||
1537232052,,ui,info,state | ||
1537232052,,ui,info,directory | ||
1537232052,,ui,info, | ||
1537232052,,ui,info,------------------------------------------------------------------------- | ||
1537232052,,ui,info,18a7399 | ||
1537232052,,ui,info,box-0 | ||
1537232052,,ui,info,virtualbox | ||
1537232052,,ui,info,running | ||
1537232052,,ui,info,/path/to/box/0 | ||
1537232052,,ui,info, | ||
1537232052,,ui,info,3bf0e6a | ||
1537232052,,ui,info,box-1 | ||
1537232052,,ui,info,virtualbox | ||
1537232052,,ui,info,running | ||
1537232052,,ui,info,/path/to/box/1 | ||
1537232052,,ui,info, | ||
1537232052,,ui,info,dc1c471 | ||
1537232052,,ui,info,box-2 | ||
1537232052,,ui,info,virtualbox | ||
1537232052,,ui,info,running | ||
1537232052,,ui,info,/path/to/box/2 | ||
1537232052,,ui,info, | ||
1537232052,,ui,info, \nThe above shows information about all known Vagrant environments\non this machine. This data is cached and may not be completely\nup-to-date (use "vagrant global-status --prune" to prune invalid\nentries). To interact with any of the machines%!(VAGRANT_COMMA) you can go to that\ndirectory and run Vagrant%!(VAGRANT_COMMA) or you can use the ID directly with\nVagrant commands from any directory. For example:\n"vagrant destroy 1a2b3c4d" | ||
` | ||
} | ||
|
||
func TestGlobalStatusCommand_buildArguments(t *testing.T) { | ||
client := newMockVagrantClient() | ||
|
||
t.Run("prune", func(t *testing.T) { | ||
cmd := client.GlobalStatus() | ||
cmd.Prune = true | ||
args := cmd.buildArguments() | ||
assertArguments(t, args, "--prune") | ||
}) | ||
} | ||
|
||
func TestGlobalStatusCommand_Run(t *testing.T) { | ||
client := newMockVagrantClient() | ||
cmd := client.GlobalStatus() | ||
if err := cmd.Run(); err != nil { | ||
t.Fatalf("Command failed to run: %v", err) | ||
} | ||
if cmd.Error != nil { | ||
t.Fatalf("Command returned error: %v", cmd.Error) | ||
} | ||
|
||
if len(cmd.Status) != 3 { | ||
t.Fatalf("Expected 3 statuses; got %v", len(cmd.Status)) | ||
} | ||
|
||
status, ok := cmd.Status["3bf0e6a"] | ||
if !ok { | ||
t.Fatalf("Expected status for '3bf0e6a' VM") | ||
} | ||
|
||
if status.Name != "box-1" { | ||
t.Errorf("Expected name to be 'box-1'; got %v", status.Name) | ||
} | ||
if status.Provider != "virtualbox" { | ||
t.Errorf("Expected provider to be 'virtualbox'; got %v", status.Provider) | ||
} | ||
if status.State != "running" { | ||
t.Errorf("Expected state to be 'running'; got %v", status.State) | ||
} | ||
if status.Directory != "/path/to/box/1" { | ||
t.Errorf("Expected directory to be '/path/to/box/1'; got %v", status.Directory) | ||
} | ||
} |