fission 0.4.0 → 0.5.0.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. data/.ruby-gemset +1 -0
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +12 -3
  5. data/README.md +45 -19
  6. data/bin/fission +1 -1
  7. data/fission.gemspec +3 -2
  8. data/lib/fission.rb +15 -0
  9. data/lib/fission/action/shell_executor.rb +37 -0
  10. data/lib/fission/action/snapshot/creator.rb +81 -0
  11. data/lib/fission/action/snapshot/deleter.rb +85 -0
  12. data/lib/fission/action/snapshot/lister.rb +90 -0
  13. data/lib/fission/action/snapshot/reverter.rb +81 -0
  14. data/lib/fission/action/vm/cloner.rb +191 -0
  15. data/lib/fission/action/vm/deleter.rb +73 -0
  16. data/lib/fission/action/vm/lister.rb +138 -0
  17. data/lib/fission/action/vm/starter.rb +88 -0
  18. data/lib/fission/action/vm/stopper.rb +79 -0
  19. data/lib/fission/action/vm/suspender.rb +68 -0
  20. data/lib/fission/cli.rb +21 -117
  21. data/lib/fission/command.rb +39 -0
  22. data/lib/fission/command/clone.rb +11 -6
  23. data/lib/fission/command/delete.rb +11 -6
  24. data/lib/fission/command/info.rb +62 -0
  25. data/lib/fission/command/snapshot_create.rb +9 -3
  26. data/lib/fission/command/snapshot_delete.rb +38 -0
  27. data/lib/fission/command/snapshot_list.rb +9 -3
  28. data/lib/fission/command/snapshot_revert.rb +9 -3
  29. data/lib/fission/command/start.rb +11 -6
  30. data/lib/fission/command/status.rb +9 -1
  31. data/lib/fission/command/stop.rb +9 -3
  32. data/lib/fission/command/suspend.rb +11 -6
  33. data/lib/fission/command_helpers.rb +18 -4
  34. data/lib/fission/command_line_parser.rb +189 -0
  35. data/lib/fission/config.rb +1 -1
  36. data/lib/fission/fusion.rb +3 -4
  37. data/lib/fission/lease.rb +2 -1
  38. data/lib/fission/metadata.rb +6 -1
  39. data/lib/fission/response.rb +17 -9
  40. data/lib/fission/version.rb +1 -1
  41. data/lib/fission/vm.rb +142 -382
  42. data/lib/fission/vm_configuration.rb +79 -0
  43. data/spec/fission/action/execute_shell_command_spec.rb +25 -0
  44. data/spec/fission/action/snapshot/creator_spec.rb +77 -0
  45. data/spec/fission/action/snapshot/deleter_spec.rb +84 -0
  46. data/spec/fission/action/snapshot/lister_spec.rb +67 -0
  47. data/spec/fission/action/snapshot/reverter_spec.rb +76 -0
  48. data/spec/fission/action/vm/cloner_spec.rb +198 -0
  49. data/spec/fission/action/vm/deleter_spec.rb +79 -0
  50. data/spec/fission/action/vm/lister_spec.rb +164 -0
  51. data/spec/fission/action/vm/starter_spec.rb +88 -0
  52. data/spec/fission/action/vm/stopper_spec.rb +71 -0
  53. data/spec/fission/action/vm/suspender_spec.rb +59 -0
  54. data/spec/fission/cli_spec.rb +32 -157
  55. data/spec/fission/command/clone_spec.rb +9 -3
  56. data/spec/fission/command/delete_spec.rb +11 -3
  57. data/spec/fission/command/info_spec.rb +130 -0
  58. data/spec/fission/command/snapshot_create_spec.rb +11 -3
  59. data/spec/fission/command/snapshot_delete_spec.rb +74 -0
  60. data/spec/fission/command/snapshot_list_spec.rb +11 -3
  61. data/spec/fission/command/snapshot_revert_spec.rb +11 -3
  62. data/spec/fission/command/start_spec.rb +11 -3
  63. data/spec/fission/command/status_spec.rb +16 -5
  64. data/spec/fission/command/stop_spec.rb +11 -3
  65. data/spec/fission/command/suspend_spec.rb +11 -3
  66. data/spec/fission/command_helpers_spec.rb +27 -5
  67. data/spec/fission/command_line_parser_spec.rb +267 -0
  68. data/spec/fission/command_spec.rb +16 -1
  69. data/spec/fission/config_spec.rb +3 -3
  70. data/spec/fission/fusion_spec.rb +11 -6
  71. data/spec/fission/lease_spec.rb +81 -45
  72. data/spec/fission/metadata_spec.rb +29 -6
  73. data/spec/fission/response_spec.rb +20 -9
  74. data/spec/fission/ui_spec.rb +1 -1
  75. data/spec/fission/vm_configuration_spec.rb +132 -0
  76. data/spec/fission/vm_spec.rb +393 -750
  77. data/spec/helpers/command_helpers.rb +1 -1
  78. metadata +93 -15
  79. data/.rvmrc +0 -1
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fission::Action::VM::Deleter do
4
+
5
+ describe 'delete' do
6
+ before do
7
+ @vm = Fission::VM.new 'foo'
8
+ @vmrun_cmd = Fission.config['vmrun_cmd']
9
+ @conf_file_path = File.join @vm.path, 'foo.vmx'
10
+ @conf_file_response_mock = mock 'conf_file_response'
11
+ @running_response_mock = mock 'running?'
12
+ @vm_files = %w{ .vmx .vmxf .vmdk -s001.vmdk -s002.vmdk .vmsd }
13
+
14
+ @vm.stub(:exists?).and_return(true)
15
+ @vm.stub(:running?).and_return(@running_response_mock)
16
+ @vm.stub(:conf_file).and_return(@conf_file_response_mock)
17
+ @running_response_mock.stub_as_successful false
18
+ @conf_file_response_mock.stub_as_successful @conf_file_path
19
+ @deleter = Fission::Action::VM::Deleter.new @vm
20
+
21
+ FakeFS.activate!
22
+
23
+ FileUtils.mkdir_p @vm.path
24
+
25
+ @vm_files.each do |file|
26
+ FileUtils.touch File.join(@vm.path, "#{@vm.name}#{file}")
27
+ end
28
+ end
29
+
30
+ after do
31
+ FakeFS.deactivate!
32
+ end
33
+
34
+ it "should return an unsuccessful response if the vm doesn't exist" do
35
+ @vm.stub(:exists?).and_return(false)
36
+
37
+ response = @deleter.delete
38
+ response.should be_an_unsuccessful_response 'VM does not exist'
39
+ end
40
+
41
+ it 'should return an unsuccessful response if the vm is running' do
42
+ @running_response_mock.stub_as_successful true
43
+
44
+ response = @deleter.delete
45
+ response.should be_an_unsuccessful_response 'The VM must not be running in order to delete it.'
46
+ end
47
+
48
+ it 'should return an unsuccessful response if unable to determine if running' do
49
+ @running_response_mock.stub_as_unsuccessful
50
+
51
+ response = @deleter.delete
52
+ response.should be_an_unsuccessful_response
53
+ end
54
+
55
+ it "should delete the target vm files" do
56
+ Fission::Metadata.stub!(:delete_vm_info)
57
+
58
+ @deleter.delete
59
+
60
+ @vm_files.each do |file|
61
+ file_path = File.join @vm.path, "#{@vm.name}#{file}"
62
+ File.exists?(file_path).should == false
63
+ end
64
+
65
+ File.directory?(@vm.path).should == false
66
+ end
67
+
68
+ it 'should delete the target vm metadata' do
69
+ Fission::Metadata.should_receive(:delete_vm_info).with(@vm.path)
70
+ @deleter.delete
71
+ end
72
+
73
+ it 'should return a successful reponse object' do
74
+ Fission::Metadata.stub!(:delete_vm_info)
75
+ @deleter.delete.should be_a_successful_response
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fission::Action::VM::Lister do
4
+ before do
5
+ @vm_1 = Fission::VM.new 'foo'
6
+ @vm_2 = Fission::VM.new 'bar'
7
+ @vm_3 = Fission::VM.new 'baz'
8
+ @lister = Fission::Action::VM::Lister.new
9
+ end
10
+
11
+ describe 'all' do
12
+ before do
13
+ @vm_1_mock = mock('vm_1')
14
+ @vm_2_mock = mock('vm_2')
15
+ @vm_root = Fission.config['vm_dir']
16
+ @vm_dirs = ['foo.vmwarevm', 'bar.vmwarevm'].map do |d|
17
+ File.join(@vm_root, d)
18
+ end
19
+ end
20
+
21
+ it "should return a successful response with the list of VM objects" do
22
+ Dir.should_receive(:[]).and_return(@vm_dirs)
23
+ @vm_dirs.each do |dir|
24
+ File.should_receive(:directory?).with(dir).and_return(true)
25
+ end
26
+
27
+ Fission::VM.should_receive(:new).with('foo').and_return(@vm_1_mock)
28
+ Fission::VM.should_receive(:new).with('bar').and_return(@vm_2_mock)
29
+
30
+ response = @lister.all
31
+ response.should be_a_successful_response
32
+ response.data.should == [@vm_1_mock, @vm_2_mock]
33
+ end
34
+
35
+ it "should not return an item in the list if it isn't a directory" do
36
+ @vm_dirs << File.join(@vm_root, 'baz.vmwarevm')
37
+ Dir.should_receive(:[]).and_return(@vm_dirs)
38
+ @vm_dirs.each do |dir|
39
+ if dir =~ /baz/
40
+ File.should_receive(:directory?).with(dir).and_return(false)
41
+ else
42
+ File.should_receive(:directory?).with(dir).and_return(true)
43
+ end
44
+ end
45
+
46
+ Fission::VM.should_receive(:new).with('foo').and_return(@vm_1_mock)
47
+ Fission::VM.should_receive(:new).with('bar').and_return(@vm_2_mock)
48
+
49
+ response = @lister.all
50
+ response.should be_a_successful_response
51
+ response.data.should == [@vm_1_mock, @vm_2_mock]
52
+ end
53
+
54
+ it "should only query for items with an extension of .vmwarevm" do
55
+ dir_arg = File.join Fission.config['vm_dir'], '*.vmwarevm'
56
+ Dir.should_receive(:[]).with(dir_arg).and_return([])
57
+ @lister.all
58
+ end
59
+ end
60
+
61
+ describe 'all running' do
62
+ before do
63
+ @vmrun_cmd = Fission.config['vmrun_cmd']
64
+ @vm_names_and_objs = { 'foo' => @vm_1, 'bar' => @vm_2, 'baz' => @vm_3 }
65
+ @executor = mock 'executor'
66
+ @process_status = mock 'process status'
67
+ end
68
+
69
+ it 'should return a successful response with the list of running vms' do
70
+ list_output = "Total running VMs: 2\n/vm/foo.vmwarevm/foo.vmx\n"
71
+ list_output << "/vm/bar.vmwarevm/bar.vmx\n/vm/baz.vmwarevm/baz.vmx\n"
72
+ Fission::Action::ShellExecutor.should_receive(:new).
73
+ with("#{@vmrun_cmd} list").
74
+ and_return(@executor)
75
+ @process_status.should_receive(:exitstatus).and_return(0)
76
+ @executor.should_receive(:execute).
77
+ and_return({'process_status' => @process_status,
78
+ 'output' => list_output})
79
+
80
+ [ 'foo', 'bar', 'baz'].each do |vm|
81
+ File.should_receive(:exists?).with("/vm/#{vm}.vmwarevm/#{vm}.vmx").
82
+ and_return(true)
83
+
84
+ Fission::VM.should_receive(:new).with(vm).
85
+ and_return(@vm_names_and_objs[vm])
86
+ end
87
+
88
+ response = @lister.all_running
89
+ response.should be_a_successful_response
90
+ response.data.should == [@vm_1, @vm_2, @vm_3]
91
+ end
92
+
93
+ it 'should return a successful response with the VM dir name if it differs from the .vmx file name' do
94
+ vm_dir_file = { 'foo' => 'foo', 'bar' => 'diff', 'baz' => 'baz'}
95
+ list_output = "Total running VMs: 3\n"
96
+ vm_dir_file.each_pair do |dir, file|
97
+ list_output << "/vm/#{dir}.vmwarevm/#{file}.vmx\n"
98
+ File.should_receive(:exists?).with("/vm/#{dir}.vmwarevm/#{file}.vmx").
99
+ and_return(true)
100
+ Fission::VM.should_receive(:new).with(dir).
101
+ and_return(@vm_names_and_objs[dir])
102
+ end
103
+
104
+ Fission::Action::ShellExecutor.should_receive(:new).
105
+ with("#{@vmrun_cmd} list").
106
+ and_return(@executor)
107
+ @process_status.should_receive(:exitstatus).and_return(0)
108
+ @executor.should_receive(:execute).
109
+ and_return({'process_status' => @process_status,
110
+ 'output' => list_output})
111
+
112
+ response = @lister.all_running
113
+ response.should be_a_successful_response
114
+ response.data.should =~ [@vm_1, @vm_2, @vm_3]
115
+ end
116
+
117
+ it 'should return an unsuccessful response if unable to get the list of running vms' do
118
+ Fission::Action::ShellExecutor.should_receive(:new).
119
+ with("#{@vmrun_cmd} list").
120
+ and_return(@executor)
121
+ @process_status.should_receive(:exitstatus).and_return(1)
122
+ @executor.should_receive(:execute).
123
+ and_return({'process_status' => @process_status,
124
+ 'output' => 'it blew up'})
125
+ @lister.all_running.should be_an_unsuccessful_response
126
+ end
127
+
128
+ end
129
+
130
+ describe 'all_with_status' do
131
+ before do
132
+ @all_running_response_mock = mock('all_running_mock')
133
+ @all_vms_response_mock = mock('all_vms_mock')
134
+
135
+ @all_vms_response_mock.stub_as_successful [@vm_1, @vm_2, @vm_3]
136
+ @all_running_response_mock.stub_as_successful [@vm_1]
137
+
138
+ @vm_2.stub(:suspend_file_exists?).and_return('true')
139
+ @lister.stub(:all).and_return(@all_vms_response_mock)
140
+ @lister.stub(:all_running).and_return(@all_running_response_mock)
141
+ end
142
+
143
+ it 'should return a sucessful response with the VMs and their status' do
144
+ response = @lister.all_with_status
145
+ response.should be_a_successful_response
146
+ response.data.should == { 'foo' => 'running',
147
+ 'bar' => 'suspended',
148
+ 'baz' => 'not running' }
149
+
150
+ end
151
+
152
+ it 'should return an unsuccessful response if unable to get all of the VMs' do
153
+ @all_vms_response_mock.stub_as_unsuccessful
154
+ @lister.all_with_status.should be_an_unsuccessful_response
155
+ end
156
+
157
+ it 'should return an unsuccessful repsonse if unable to get the running VMs' do
158
+ @all_running_response_mock.stub_as_unsuccessful
159
+ @lister.all_with_status.should be_an_unsuccessful_response
160
+ end
161
+
162
+ end
163
+
164
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fission::Action::VM::Starter do
4
+
5
+ describe 'start' do
6
+ before do
7
+ @vm = Fission::VM.new 'foo'
8
+ @vmrun_cmd = Fission.config['vmrun_cmd']
9
+ @conf_file_path = File.join @vm.path, 'foo.vmx'
10
+ @conf_file_response_mock = mock 'conf_file_response'
11
+ @running_response_mock = mock 'running?'
12
+
13
+ @vm.stub(:exists?).and_return(true)
14
+ @vm.stub(:running?).and_return(@running_response_mock)
15
+ @vm.stub(:conf_file).and_return(@conf_file_response_mock)
16
+ @running_response_mock.stub_as_successful false
17
+ @conf_file_response_mock.stub_as_successful @conf_file_path
18
+ @starter = Fission::Action::VM::Starter.new @vm
19
+ end
20
+
21
+ it "should return an unsuccessful response if the vm doesn't exist" do
22
+ @vm.stub(:exists?).and_return(false)
23
+ @starter.start.should be_an_unsuccessful_response 'VM does not exist'
24
+ end
25
+
26
+ it 'should return an unsuccessful response if the vm is already running' do
27
+ @running_response_mock.stub_as_successful true
28
+ @starter.start.should be_an_unsuccessful_response 'VM is already running'
29
+ end
30
+
31
+ it 'should return an unsuccessful response if unable to determine if running' do
32
+ @running_response_mock.stub_as_unsuccessful
33
+ @starter.start.should be_an_unsuccessful_response
34
+ end
35
+
36
+ it 'should return an unsuccessful response if unable to figure out the conf file' do
37
+ @conf_file_response_mock.stub_as_unsuccessful
38
+ @starter.start.should be_an_unsuccessful_response
39
+ end
40
+
41
+ context 'when the fusion gui is not running' do
42
+ before do
43
+ @executor_mock = mock 'executor'
44
+ @response = stub
45
+ @executor_mock.should_receive(:execute).and_return(@executor_mock)
46
+ Fission::Fusion.stub(:running?).and_return(false)
47
+ Fission::Response.should_receive(:from_shell_executor).
48
+ with(@executor_mock).
49
+ and_return(@response)
50
+ end
51
+
52
+ it 'should return a response when starting the vm' do
53
+ cmd = "#{@vmrun_cmd} start '#{@conf_file_path}' gui 2>&1"
54
+ Fission::Action::ShellExecutor.should_receive(:new).
55
+ with(cmd).
56
+ and_return(@executor_mock)
57
+ @starter.start.should == @response
58
+ end
59
+
60
+ it 'should return a response when starting the vm headless' do
61
+ cmd = "#{@vmrun_cmd} start '#{@conf_file_path}' nogui 2>&1"
62
+ Fission::Action::ShellExecutor.should_receive(:new).
63
+ with(cmd).
64
+ and_return(@executor_mock)
65
+ @starter.start(:headless => true).should == @response
66
+ end
67
+
68
+ end
69
+
70
+ context 'when the fusion gui is running' do
71
+ before do
72
+ Fission::Fusion.stub(:running?).and_return(true)
73
+ end
74
+
75
+ it 'should return an unsuccessful response if starting headless' do
76
+ response = @starter.start :headless => true
77
+
78
+ error_string = 'It looks like the Fusion GUI is currently running. '
79
+ error_string << 'A VM cannot be started in headless mode when the Fusion GUI is running. '
80
+ error_string << 'Exit the Fusion GUI and try again.'
81
+
82
+ response.should be_an_unsuccessful_response error_string
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fission::Action::VM::Stopper do
4
+
5
+ describe 'stop' do
6
+ before do
7
+ @vm = Fission::VM.new 'foo'
8
+ @vmrun_cmd = Fission.config['vmrun_cmd']
9
+ @conf_file_path = File.join @vm.path, 'foo.vmx'
10
+ @conf_file_response_mock = mock 'conf_file_response'
11
+ @running_response_mock = mock 'running?'
12
+
13
+ @vm.stub(:exists?).and_return(true)
14
+ @vm.stub(:running?).and_return(@running_response_mock)
15
+ @vm.stub(:conf_file).and_return(@conf_file_response_mock)
16
+ @running_response_mock.stub_as_successful true
17
+ @conf_file_response_mock.stub_as_successful @conf_file_path
18
+ @stopper = Fission::Action::VM::Stopper.new @vm
19
+ end
20
+
21
+ it "should return an unsuccessful response if the vm doesn't exist" do
22
+ @vm.stub(:exists?).and_return(false)
23
+ @stopper.stop.should be_an_unsuccessful_response 'VM does not exist'
24
+ end
25
+
26
+ it 'should return an unsuccessful response if the vm is not running' do
27
+ @running_response_mock.stub_as_successful false
28
+ @stopper.stop.should be_an_unsuccessful_response 'VM is not running'
29
+ end
30
+
31
+ it 'should return an unsuccessful response if unable to determine if running' do
32
+ @running_response_mock.stub_as_unsuccessful
33
+ @stopper.stop.should be_an_unsuccessful_response
34
+ end
35
+
36
+ it 'should return an unsuccessful response if unable to figure out the conf file' do
37
+ @conf_file_response_mock.stub_as_unsuccessful
38
+ @stopper.stop.should be_an_unsuccessful_response
39
+ end
40
+
41
+ context 'when stopping the vm' do
42
+ before do
43
+ @executor_mock = mock 'executor'
44
+ @response = stub
45
+ @executor_mock.should_receive(:execute).and_return(@executor_mock)
46
+ Fission::Fusion.stub(:running?).and_return(false)
47
+ Fission::Response.should_receive(:from_shell_executor).
48
+ with(@executor_mock).
49
+ and_return(@response)
50
+ end
51
+
52
+ it 'should return a response' do
53
+ cmd = "#{@vmrun_cmd} stop '#{@conf_file_path}' 2>&1"
54
+ Fission::Action::ShellExecutor.should_receive(:new).
55
+ with(cmd).
56
+ and_return(@executor_mock)
57
+ @stopper.stop.should == @response
58
+ end
59
+
60
+ it 'should return a response for a hard stop' do
61
+ cmd = "#{@vmrun_cmd} stop '#{@conf_file_path}' hard 2>&1"
62
+ Fission::Action::ShellExecutor.should_receive(:new).
63
+ with(cmd).
64
+ and_return(@executor_mock)
65
+ @stopper.stop(:hard => true).should == @response
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fission::Action::VM::Suspender do
4
+
5
+ describe 'suspend' do
6
+ before do
7
+ @vm = Fission::VM.new 'foo'
8
+ @vmrun_cmd = Fission.config['vmrun_cmd']
9
+ @conf_file_path = File.join @vm.path, 'foo.vmx'
10
+ @conf_file_response_mock = mock 'conf_file_response'
11
+ @running_response_mock = mock 'running?'
12
+
13
+ @vm.stub(:exists?).and_return(true)
14
+ @vm.stub(:running?).and_return(@running_response_mock)
15
+ @vm.stub(:conf_file).and_return(@conf_file_response_mock)
16
+ @running_response_mock.stub_as_successful true
17
+ @conf_file_response_mock.stub_as_successful @conf_file_path
18
+ @suspender = Fission::Action::VM::Suspender.new @vm
19
+ end
20
+
21
+ it "should return an unsuccessful response if the vm doesn't exist" do
22
+ @vm.stub(:exists?).and_return(false)
23
+ @suspender.suspend.should be_an_unsuccessful_response 'VM does not exist'
24
+ end
25
+
26
+ it 'should return an unsuccessful response if the vm is not running' do
27
+ @running_response_mock.stub_as_successful false
28
+ @suspender.suspend.should be_an_unsuccessful_response 'VM is not running'
29
+ end
30
+
31
+ it 'should return an unsuccessful response if unable to determine if running' do
32
+ @running_response_mock.stub_as_unsuccessful
33
+ @suspender.suspend.should be_an_unsuccessful_response
34
+ end
35
+
36
+ it 'should return an unsuccessful response if unable to figure out the conf file' do
37
+ @conf_file_response_mock.stub_as_unsuccessful
38
+ @suspender.suspend.should be_an_unsuccessful_response
39
+ end
40
+
41
+ it 'should return a response' do
42
+ executor_mock = mock 'executor'
43
+ response = stub
44
+ cmd = "#{@vmrun_cmd} suspend "
45
+ cmd << "'#{@conf_file_path}' 2>&1"
46
+
47
+ executor_mock.should_receive(:execute).and_return(executor_mock)
48
+ Fission::Action::ShellExecutor.should_receive(:new).
49
+ with(cmd).
50
+ and_return(executor_mock)
51
+ Fission::Response.should_receive(:from_shell_executor).
52
+ with(executor_mock).
53
+ and_return(response)
54
+ @suspender.suspend.should == response
55
+ end
56
+
57
+ end
58
+
59
+ end