fission 0.4.0 → 0.5.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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