fission-0.5.0/0000755000076400007640000000000012511713252012221 5ustar pravipravifission-0.5.0/spec/0000755000076400007640000000000012511713252013153 5ustar pravipravifission-0.5.0/spec/spec_helper.rb0000644000076400007640000000037212511713252015773 0ustar pravipravirequire 'rspec' require 'fission' require 'fakefs/safe' ['contexts', 'helpers', 'matchers'].each do |dir| Dir[File.expand_path(File.join(File.dirname(__FILE__),dir,'*.rb'))].each {|f| require f} end include ResponseHelpers include CommandHelpers fission-0.5.0/spec/contexts/0000755000076400007640000000000012511713252015022 5ustar pravipravifission-0.5.0/spec/contexts/command.rb0000644000076400007640000000050612511713252016766 0ustar pravipravishared_context 'command_setup' do before do @string_io = StringIO.new ui_stub = Fission::UI.new(@string_io) Fission::UI.stub(:new).and_return(ui_stub) @all_running_response_mock = double('all_running_response') @state_response_mock = double('state_response') @vm_mock = double('vm_mock') end end fission-0.5.0/spec/matchers/0000755000076400007640000000000012511713252014761 5ustar pravipravifission-0.5.0/spec/matchers/be_an_unsuccessful_response.rb0000644000076400007640000000035612511713252023076 0ustar pravipraviRSpec::Matchers.define :be_an_unsuccessful_response do |message| message ||= 'it blew up' match do |actual| actual.successful? == false && actual.code == 1 && actual.message == message && actual.data == nil end end fission-0.5.0/spec/matchers/be_a_successful_response.rb0000644000076400007640000000024512511713252022352 0ustar pravipraviRSpec::Matchers.define :be_a_successful_response do match do |actual| actual.successful? == true && actual.code == 0 && actual.message == '' end end fission-0.5.0/spec/fission_spec.rb0000644000076400007640000000025512511713252016166 0ustar pravipravirequire 'spec_helper' describe Fission do describe "config" do it "should load a config object" do Fission.config.should be_a Fission::Config end end end fission-0.5.0/spec/helpers/0000755000076400007640000000000012511713252014615 5ustar pravipravifission-0.5.0/spec/helpers/command_helpers.rb0000644000076400007640000000065512511713252020310 0ustar pravipravimodule CommandHelpers def it_should_not_accept_arguments_of(args, command_name) it "should output an error and the help when #{args.count} arguments are passed in" do subject.should_receive(:help) command = subject.new args lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /[Incorrect arguments for #{command_name} command|invalid option]/ end end end fission-0.5.0/spec/helpers/response_helpers.rb0000644000076400007640000000111712511713252020522 0ustar pravipravimodule ResponseHelpers def stub_response_mock_with(args={}) args.each_pair do |method, data| stub(method).and_return(data) end end def stub_as_successful(data=nil) stub_response_mock_with :code => 0, :message => '', :successful? => true, :data => data end def stub_as_unsuccessful stub_response_mock_with :code => 1, :message => 'it blew up', :successful? => false, :data => nil end end fission-0.5.0/spec/fission/0000755000076400007640000000000012511713252014625 5ustar pravipravifission-0.5.0/spec/fission/fusion_spec.rb0000644000076400007640000000177212511713252017476 0ustar pravipravirequire 'spec_helper' describe Fission::Fusion do describe 'self.running?' do before do @cmd = "ps -ef | grep -v grep | " @cmd << "grep -c '#{Fission.config['gui_bin']}' 2>&1" @executor = double('executor') end it 'should return a successful response and true if the fusion app is running' do @executor.should_receive(:execute).and_return({'output' => "1\n"}) Fission::Action::ShellExecutor.should_receive(:new). with(@cmd). and_return(@executor) Fission::Fusion.running?.should == true end it 'should return a successful response and false if the fusion app is not running' do @executor.should_receive(:execute).and_return({'output' => "0\n"}) Fission::Action::ShellExecutor.should_receive(:new). with(@cmd). and_return(@executor) Fission::Fusion.running?.should == false end end end fission-0.5.0/spec/fission/action/0000755000076400007640000000000012511713252016102 5ustar pravipravifission-0.5.0/spec/fission/action/execute_shell_command_spec.rb0000644000076400007640000000112512511713252023767 0ustar pravipravirequire 'spec_helper' describe Fission::Action::ShellExecutor do describe 'execute' do before do @cmd = 'ls /var/log' @executor = Fission::Action::ShellExecutor.new @cmd end it 'should execute the shell command' do @executor.should_receive(:`).with(@cmd) @executor.execute end it 'should return a hash of the output and Process::Status object' do result = @executor.execute result['output'].should be_a String result['output'].empty?.should be_false result['process_status'].should be_a Process::Status end end end fission-0.5.0/spec/fission/action/vm/0000755000076400007640000000000012511713252016524 5ustar pravipravifission-0.5.0/spec/fission/action/vm/starter_spec.rb0000644000076400007640000000645312511713252021557 0ustar pravipravirequire 'spec_helper' describe Fission::Action::VM::Starter do describe 'start' do before do @vm = Fission::VM.new 'foo' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_path = File.join @vm.path, 'foo.vmx' @conf_file_response_mock = double('conf_file_response') @running_response_mock = double('running?') @vm.stub(:exists?).and_return(true) @vm.stub(:running?).and_return(@running_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) @running_response_mock.stub_as_successful false @conf_file_response_mock.stub_as_successful @conf_file_path @starter = Fission::Action::VM::Starter.new @vm end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @starter.start.should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if the vm is already running' do @running_response_mock.stub_as_successful true @starter.start.should be_an_unsuccessful_response 'VM is already running' end it 'should return an unsuccessful response if unable to determine if running' do @running_response_mock.stub_as_unsuccessful @starter.start.should be_an_unsuccessful_response end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @starter.start.should be_an_unsuccessful_response end context 'when the fusion gui is not running' do before do @executor_mock = double('executor') @response = double @executor_mock.should_receive(:execute).and_return(@executor_mock) Fission::Fusion.stub(:running?).and_return(false) Fission::Response.should_receive(:from_shell_executor). with(@executor_mock). and_return(@response) end it 'should return a response when starting the vm' do cmd = "#{@vmrun_cmd} start '#{@conf_file_path}' gui 2>&1" Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(@executor_mock) @starter.start.should == @response end it 'should return a response when starting the vm headless' do cmd = "#{@vmrun_cmd} start '#{@conf_file_path}' nogui 2>&1" Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(@executor_mock) @starter.start(:headless => true).should == @response end end context 'when the fusion gui is running' do before do Fission::Fusion.stub(:running?).and_return(true) end it 'should return an unsuccessful response if starting headless' do response = @starter.start :headless => true error_string = 'It looks like the Fusion GUI is currently running. ' error_string << 'A VM cannot be started in headless mode when the Fusion GUI is running. ' error_string << 'Exit the Fusion GUI and try again.' response.should be_an_unsuccessful_response error_string end end end end fission-0.5.0/spec/fission/action/vm/lister_spec.rb0000644000076400007640000001425512511713252021374 0ustar pravipravirequire 'spec_helper' describe Fission::Action::VM::Lister do before do @vm_1 = Fission::VM.new 'foo' @vm_2 = Fission::VM.new 'bar' @vm_3 = Fission::VM.new 'baz' @lister = Fission::Action::VM::Lister.new end describe 'all' do before do @vm_1_mock = double('vm_1') @vm_2_mock = double('vm_2') @vm_root = Fission.config['vm_dir'] @vm_dirs = ['foo.vmwarevm', 'bar.vmwarevm'].map do |d| File.join(@vm_root, d) end end it "should return a successful response with the list of VM objects" do Dir.should_receive(:[]).and_return(@vm_dirs) @vm_dirs.each do |dir| File.should_receive(:directory?).with(dir).and_return(true) end Fission::VM.should_receive(:new).with('foo').and_return(@vm_1_mock) Fission::VM.should_receive(:new).with('bar').and_return(@vm_2_mock) response = @lister.all response.should be_a_successful_response response.data.should == [@vm_1_mock, @vm_2_mock] end it "should not return an item in the list if it isn't a directory" do @vm_dirs << File.join(@vm_root, 'baz.vmwarevm') Dir.should_receive(:[]).and_return(@vm_dirs) @vm_dirs.each do |dir| if dir =~ /baz/ File.should_receive(:directory?).with(dir).and_return(false) else File.should_receive(:directory?).with(dir).and_return(true) end end Fission::VM.should_receive(:new).with('foo').and_return(@vm_1_mock) Fission::VM.should_receive(:new).with('bar').and_return(@vm_2_mock) response = @lister.all response.should be_a_successful_response response.data.should == [@vm_1_mock, @vm_2_mock] end it "should only query for items with an extension of .vmwarevm" do dir_arg = File.join Fission.config['vm_dir'], '*.vmwarevm' Dir.should_receive(:[]).with(dir_arg).and_return([]) @lister.all end end describe 'all running' do before do @vmrun_cmd = Fission.config['vmrun_cmd'] @vm_names_and_objs = { 'foo' => @vm_1, 'bar' => @vm_2, 'baz' => @vm_3 } @executor = double('executor') @process_status = double('process status') end it 'should return a successful response with the list of running vms' do list_output = "Total running VMs: 2\n/vm/foo.vmwarevm/foo.vmx\n" list_output << "/vm/bar.vmwarevm/bar.vmx\n/vm/baz.vmwarevm/baz.vmx\n" Fission::Action::ShellExecutor.should_receive(:new). with("#{@vmrun_cmd} list"). and_return(@executor) @process_status.should_receive(:exitstatus).and_return(0) @executor.should_receive(:execute). and_return({'process_status' => @process_status, 'output' => list_output}) [ 'foo', 'bar', 'baz'].each do |vm| File.should_receive(:exists?).with("/vm/#{vm}.vmwarevm/#{vm}.vmx"). and_return(true) Fission::VM.should_receive(:new).with(vm). and_return(@vm_names_and_objs[vm]) end response = @lister.all_running response.should be_a_successful_response response.data.should == [@vm_1, @vm_2, @vm_3] end it 'should return a successful response with the VM dir name if it differs from the .vmx file name' do vm_dir_file = { 'foo' => 'foo', 'bar' => 'diff', 'baz' => 'baz'} list_output = "Total running VMs: 3\n" vm_dir_file.each_pair do |dir, file| list_output << "/vm/#{dir}.vmwarevm/#{file}.vmx\n" File.should_receive(:exists?).with("/vm/#{dir}.vmwarevm/#{file}.vmx"). and_return(true) Fission::VM.should_receive(:new).with(dir). and_return(@vm_names_and_objs[dir]) end Fission::Action::ShellExecutor.should_receive(:new). with("#{@vmrun_cmd} list"). and_return(@executor) @process_status.should_receive(:exitstatus).and_return(0) @executor.should_receive(:execute). and_return({'process_status' => @process_status, 'output' => list_output}) response = @lister.all_running response.should be_a_successful_response response.data.should =~ [@vm_1, @vm_2, @vm_3] end it 'should return an unsuccessful response if unable to get the list of running vms' do Fission::Action::ShellExecutor.should_receive(:new). with("#{@vmrun_cmd} list"). and_return(@executor) @process_status.should_receive(:exitstatus).and_return(1) @executor.should_receive(:execute). and_return({'process_status' => @process_status, 'output' => 'it blew up'}) @lister.all_running.should be_an_unsuccessful_response end end describe 'all_with_status' do before do @all_running_response_mock = double('all_running_mock') @all_vms_response_mock = double('all_vms_mock') @all_vms_response_mock.stub_as_successful [@vm_1, @vm_2, @vm_3] @all_running_response_mock.stub_as_successful [@vm_1] @vm_2.stub(:suspend_file_exists?).and_return('true') @lister.stub(:all).and_return(@all_vms_response_mock) @lister.stub(:all_running).and_return(@all_running_response_mock) end it 'should return a sucessful response with the VMs and their status' do response = @lister.all_with_status response.should be_a_successful_response response.data.should == { 'foo' => 'running', 'bar' => 'suspended', 'baz' => 'not running' } end it 'should return an unsuccessful response if unable to get all of the VMs' do @all_vms_response_mock.stub_as_unsuccessful @lister.all_with_status.should be_an_unsuccessful_response end it 'should return an unsuccessful repsonse if unable to get the running VMs' do @all_running_response_mock.stub_as_unsuccessful @lister.all_with_status.should be_an_unsuccessful_response end end end fission-0.5.0/spec/fission/action/vm/suspender_spec.rb0000644000076400007640000000431712511713252022100 0ustar pravipravirequire 'spec_helper' describe Fission::Action::VM::Suspender do describe 'suspend' do before do @vm = Fission::VM.new 'foo' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_path = File.join @vm.path, 'foo.vmx' @conf_file_response_mock = double('conf_file_response') @running_response_mock = double('running?') @vm.stub(:exists?).and_return(true) @vm.stub(:running?).and_return(@running_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) @running_response_mock.stub_as_successful true @conf_file_response_mock.stub_as_successful @conf_file_path @suspender = Fission::Action::VM::Suspender.new @vm end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @suspender.suspend.should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if the vm is not running' do @running_response_mock.stub_as_successful false @suspender.suspend.should be_an_unsuccessful_response 'VM is not running' end it 'should return an unsuccessful response if unable to determine if running' do @running_response_mock.stub_as_unsuccessful @suspender.suspend.should be_an_unsuccessful_response end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @suspender.suspend.should be_an_unsuccessful_response end it 'should return a response' do executor_mock = double('executor') response = double cmd = "#{@vmrun_cmd} suspend " cmd << "'#{@conf_file_path}' 2>&1" executor_mock.should_receive(:execute).and_return(executor_mock) Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(executor_mock) Fission::Response.should_receive(:from_shell_executor). with(executor_mock). and_return(response) @suspender.suspend.should == response end end end fission-0.5.0/spec/fission/action/vm/deleter_spec.rb0000644000076400007640000000456412511713252021520 0ustar pravipravirequire 'spec_helper' describe Fission::Action::VM::Deleter do describe 'delete' do before do @vm = Fission::VM.new 'foo' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_path = File.join @vm.path, 'foo.vmx' @conf_file_response_mock = double('conf_file_response') @running_response_mock = double('running?') @vm_files = %w{ .vmx .vmxf .vmdk -s001.vmdk -s002.vmdk .vmsd } @vm.stub(:exists?).and_return(true) @vm.stub(:running?).and_return(@running_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) @running_response_mock.stub_as_successful false @conf_file_response_mock.stub_as_successful @conf_file_path @deleter = Fission::Action::VM::Deleter.new @vm FakeFS.activate! FileUtils.mkdir_p @vm.path @vm_files.each do |file| FileUtils.touch File.join(@vm.path, "#{@vm.name}#{file}") end end after do FakeFS.deactivate! end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) response = @deleter.delete response.should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if the vm is running' do @running_response_mock.stub_as_successful true response = @deleter.delete response.should be_an_unsuccessful_response 'The VM must not be running in order to delete it.' end it 'should return an unsuccessful response if unable to determine if running' do @running_response_mock.stub_as_unsuccessful response = @deleter.delete response.should be_an_unsuccessful_response end it "should delete the target vm files" do Fission::Metadata.stub(:delete_vm_info) @deleter.delete @vm_files.each do |file| file_path = File.join @vm.path, "#{@vm.name}#{file}" File.exists?(file_path).should == false end File.directory?(@vm.path).should == false end it 'should delete the target vm metadata' do Fission::Metadata.should_receive(:delete_vm_info).with(@vm.path) @deleter.delete end it 'should return a successful reponse object' do Fission::Metadata.stub(:delete_vm_info) @deleter.delete.should be_a_successful_response end end end fission-0.5.0/spec/fission/action/vm/cloner_spec.rb0000644000076400007640000001362012511713252021347 0ustar pravipravirequire 'spec_helper' describe Fission::Action::VM::Cloner do describe 'clone' do before do @source_vm = Fission::VM.new 'foo' @target_vm = Fission::VM.new 'bar' @source_path = @source_vm.path @target_path = @target_vm.path @clone_response_mock = double('clone_response') @vm_files = ['.vmx', '.vmxf', '.vmdk', '-s001.vmdk', '-s002.vmdk', '.vmsd'] FakeFS.activate! FileUtils.mkdir_p @source_path @vm_files.each do |file| FileUtils.touch "#{@source_path}/#{@source_vm.name}#{file}" end ['.vmx', '.vmxf', '.vmdk'].each do |ext| File.open("#{@source_path}/foo#{ext}", 'w') { |f| f.write 'foo.vmdk'} end @source_vm.stub(:exists?).and_return(true) @target_vm.stub(:exists?).and_return(false) Fission::VM.stub(:new).with(@source_vm.name). and_return(@source_vm) Fission::VM.stub(:new).with(@target_vm.name). and_return(@target_vm) vmx_content = 'ide1:0.deviceType = "cdrom-image" nvram = "foo.nvram" ethernet0.present = "TRUE" ethernet1.address = "00:0c:29:1d:6a:75" ethernet0.connectionType = "nat" ethernet0.generatedAddress = "00:0c:29:1d:6a:64" ethernet0.virtualDev = "e1000" tools.remindInstall = "TRUE" ethernet0.wakeOnPcktRcv = "FALSE" ethernet0.addressType = "generated" uuid.action = "keep" ethernet0.linkStatePropagation.enable = "TRUE" ethernet0.generatedAddressenable = "TRUE" ethernet1.generatedAddressenable = "TRUE"' File.open("#{@source_path}/#{@source_vm.name}.vmx", 'w') do |f| f.write vmx_content end ['.vmx', '.vmxf'].each do |ext| File.stub(:binary?). with("#{@target_path}/#{@target_vm.name}#{ext}"). and_return(false) end File.stub(:binary?). with("#{@target_path}/#{@target_vm.name}.vmdk"). and_return(true) @cloner = Fission::Action::VM::Cloner.new @source_vm, @target_vm end after do FakeFS.deactivate! FakeFS::FileSystem.clear end it "should return an unsuccessful response if the source vm doesn't exist" do @source_vm.stub(:exists?).and_return(false) response = @cloner.clone response.should be_an_unsuccessful_response 'VM does not exist' end it "should return an unsuccessful response if the target vm exists" do @target_vm.stub(:exists?).and_return(true) response = @cloner.clone response.should be_an_unsuccessful_response 'VM already exists' end it 'should copy the vm files to the target' do @cloner.clone File.directory?(@target_path).should == true @vm_files.each do |file| File.file?("#{@target_path}/bar#{file}").should == true end end it "should copy the vm files to the target if a file name doesn't match the directory" do FileUtils.touch "#{@source_path}/other_name.nvram" @cloner.clone File.directory?(@target_path).should == true @vm_files.each do |file| File.file?("#{@target_path}/#{@target_vm.name}#{file}").should == true end File.file?("#{@target_path}/bar.nvram").should == true end it "should copy the vm files to the target if a sparse disk file name doesn't match the directory" do FileUtils.touch "#{@source_path}/other_name-s003.vmdk" @cloner.clone File.directory?(@target_path).should == true @vm_files.each do |file| File.file?("#{@target_path}/#{@target_vm.name}#{file}").should == true end File.file?("#{@target_path}/bar-s003.vmdk").should == true end it 'should update the target vm config files' do @cloner.clone ['.vmx', '.vmxf'].each do |ext| File.read("#{@target_path}/bar#{ext}").should_not match /foo/ File.read("#{@target_path}/bar#{ext}").should match /bar/ end end it 'should disable VMware tools warning in the conf file' do @cloner.clone pattern = /^tools\.remindInstall = "FALSE"/ File.read("#{@target_path}/bar.vmx").should match pattern end it 'should remove auto generated MAC addresses from the conf file' do @cloner.clone pattern = /^ethernet\.+generatedAddress.+/ File.read("#{@target_path}/bar.vmx").should_not match pattern end it 'should setup the conf file to generate a new uuid' do @cloner.clone pattern = /^uuid\.action = "create"/ File.read("#{@target_path}/bar.vmx").scan(pattern).count.should == 1 end context 'when uuid.action already exists in the source conf file' do before do File.open("#{@source_path}/#{@source_vm.name}.vmx", 'a') do |f| f.write "\nuuid.action = \"create\"" end end it 'should not add another entry for uuid.action' do @cloner.clone pattern = /^uuid\.action = "create"/ File.read("#{@target_path}/bar.vmx").scan(pattern).count.should == 1 end end context 'when tools.remindInstall already exists in the source conf file' do before do File.open("#{@source_path}/#{@source_vm.name}.vmx", 'w') do |f| f.write "\ntools.remindInstall = \"FALSE\"" end end it 'should not add another entry for tools.remindInstall' do @cloner.clone pattern = /^tools\.remindInstall = "FALSE"/ File.read("#{@target_path}/bar.vmx").scan(pattern).count.should == 1 end end it "should not try to update the vmdk file if it's not a sparse disk" do @cloner.clone File.read("#{@target_path}/bar.vmdk").should match /foo/ end it 'should return a successful response if clone was successful' do @cloner.clone.should be_a_successful_response end context 'when a sparse disk is found' do it "should update the vmdk" do File.stub(:binary?).and_return(false) @cloner.clone File.read("#{@target_path}/bar.vmdk").should match /bar/ end end end end fission-0.5.0/spec/fission/action/vm/stopper_spec.rb0000644000076400007640000000523112511713252021560 0ustar pravipravirequire 'spec_helper' describe Fission::Action::VM::Stopper do describe 'stop' do before do @vm = Fission::VM.new 'foo' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_path = File.join @vm.path, 'foo.vmx' @conf_file_response_mock = double('conf_file_response') @running_response_mock = double('running?') @vm.stub(:exists?).and_return(true) @vm.stub(:running?).and_return(@running_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) @running_response_mock.stub_as_successful true @conf_file_response_mock.stub_as_successful @conf_file_path @stopper = Fission::Action::VM::Stopper.new @vm end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @stopper.stop.should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if the vm is not running' do @running_response_mock.stub_as_successful false @stopper.stop.should be_an_unsuccessful_response 'VM is not running' end it 'should return an unsuccessful response if unable to determine if running' do @running_response_mock.stub_as_unsuccessful @stopper.stop.should be_an_unsuccessful_response end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @stopper.stop.should be_an_unsuccessful_response end context 'when stopping the vm' do before do @executor_mock = double('executor') @response = double @executor_mock.should_receive(:execute).and_return(@executor_mock) Fission::Fusion.stub(:running?).and_return(false) Fission::Response.should_receive(:from_shell_executor). with(@executor_mock). and_return(@response) end it 'should return a response' do cmd = "#{@vmrun_cmd} stop '#{@conf_file_path}' 2>&1" Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(@executor_mock) @stopper.stop.should == @response end it 'should return a response for a hard stop' do cmd = "#{@vmrun_cmd} stop '#{@conf_file_path}' hard 2>&1" Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(@executor_mock) @stopper.stop(:hard => true).should == @response end end end end fission-0.5.0/spec/fission/action/snapshot/0000755000076400007640000000000012511713252017741 5ustar pravipravifission-0.5.0/spec/fission/action/snapshot/reverter_spec.rb0000644000076400007640000000604212511713252023140 0ustar pravipravirequire 'spec_helper' describe Fission::Action::Snapshot::Reverter do describe 'revert_snapshot' do before do @vm = Fission::VM.new 'foo' @conf_file_path = File.join @vm.path, 'foo.vmx' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_response_mock = double('conf_file_response') @snapshots_response_mock = double('snapshots') @conf_file_response_mock.stub_as_successful @conf_file_path @snapshots_response_mock.stub_as_successful [] @vm.stub(:exists?).and_return(true) @vm.stub(:snapshots).and_return(@snapshots_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) @snapshots_response_mock.stub_as_successful ['snap_1'] Fission::Fusion.stub(:running?).and_return(false) @reverter = Fission::Action::Snapshot::Reverter.new @vm end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @reverter.revert_to_snapshot('snap_1').should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if the Fusion GUI is running' do Fission::Fusion.stub(:running?).and_return(true) response = @reverter.revert_to_snapshot 'snap_1' error_string = 'It looks like the Fusion GUI is currently running. ' error_string << 'A VM cannot be reverted to a snapshot when the Fusion GUI is running.' error_string << ' Exit the Fusion GUI and try again.' response.should be_an_unsuccessful_response error_string end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @reverter.revert_to_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return a response when reverting to the snapshot' do executor_mock = double('executor') response = double cmd = "#{@vmrun_cmd} revertToSnapshot " cmd << "'#{@conf_file_path}' \"snap_1\" 2>&1" executor_mock.should_receive(:execute).and_return(executor_mock) Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(executor_mock) Fission::Response.should_receive(:from_shell_executor). with(executor_mock). and_return(response) @reverter.revert_to_snapshot('snap_1').should == response end it 'should return an unsuccessful response if the snapshot cannot be found' do @snapshots_response_mock.stub_as_successful [] response = @reverter.revert_to_snapshot 'snap_1' response.should be_an_unsuccessful_response "Unable to find a snapshot named 'snap_1'." end it 'should return an unsuccessful response if unable to list the existing snapshots' do @snapshots_response_mock.stub_as_unsuccessful @reverter.revert_to_snapshot('snap_1').should be_an_unsuccessful_response end end end fission-0.5.0/spec/fission/action/snapshot/lister_spec.rb0000644000076400007640000000501312511713252022601 0ustar pravipravirequire 'spec_helper' describe Fission::Action::Snapshot::Lister do before do @vm = Fission::VM.new 'foo' @conf_file_path = File.join @vm.path, 'foo.vmx' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_response_mock = double('conf_file_response') @vm.stub(:conf_file).and_return(@conf_file_response_mock) end describe 'snapshots' do before do @vm.stub(:exists?).and_return(true) @conf_file_response_mock.stub_as_successful @conf_file_path @lister = Fission::Action::Snapshot::Lister.new @vm end it "should return an unsuccessful repsonse when the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @lister.snapshots.should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @lister.snapshots.should be_an_unsuccessful_response end it 'should return a response when listing the snapshots' do executor_mock = double('executor') process_mock = double(:exitstatus => 0) cmd = "#{@vmrun_cmd} listSnapshots " cmd << "'#{@conf_file_path}' 2>&1" output_text = "Total snapshots: 3\nsnap foo\nsnap bar\nsnap baz\n" executor_mock.should_receive(:execute). and_return({'output' => output_text, 'process_status' => process_mock}) Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(executor_mock) response = @lister.snapshots response.should be_a_successful_response response.data.should == ['snap foo', 'snap bar', 'snap baz'] end it 'should return an unsuccessful response if there was a problem listing the snapshots' do executor_mock = double('executor') process_mock = double(:exitstatus => 1) cmd = "#{@vmrun_cmd} listSnapshots " cmd << "'#{@conf_file_path}' 2>&1" executor_mock.should_receive(:execute). and_return({'output' => 'it blew up', 'process_status' => process_mock}) Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(executor_mock) @lister.snapshots.should be_an_unsuccessful_response end end end fission-0.5.0/spec/fission/action/snapshot/deleter_spec.rb0000644000076400007640000000655512511713252022737 0ustar pravipravirequire 'spec_helper' describe Fission::Action::Snapshot::Deleter do describe 'delete_snapshot' do before do @vm = Fission::VM.new 'foo' @conf_file_path = File.join @vm.path, 'foo.vmx' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_response_mock = double('conf_file_response') @snapshots_response_mock = double('snapshots') @running_response_mock = double('running?') @running_response_mock.stub_as_successful true @conf_file_response_mock.stub_as_successful @conf_file_path @snapshots_response_mock.stub_as_successful ['snap_1'] @vm.stub(:exists?).and_return(true) @vm.stub(:snapshots).and_return(@snapshots_response_mock) @vm.stub(:running?).and_return(@running_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) Fission::Fusion.stub(:running?).and_return(false) @deleter = Fission::Action::Snapshot::Deleter.new @vm end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @deleter.delete_snapshot('snap_1').should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @deleter.delete_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return an unsuccessful response if the snapshot does not exist' do @snapshots_response_mock.stub_as_successful [] response = @deleter.delete_snapshot 'snap_1' response.should be_an_unsuccessful_response "Unable to find a snapshot named 'snap_1'." end it 'should return an unsuccessful response if there was a problem listing the existing snapshots' do @snapshots_response_mock.stub_as_unsuccessful @deleter.delete_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return a response when deleting the snapshot' do executor_mock = double('executor') response = double cmd = "#{@vmrun_cmd} deleteSnapshot " cmd << "'#{@conf_file_path}' \"snap_1\" 2>&1" executor_mock.should_receive(:execute).and_return(executor_mock) Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(executor_mock) Fission::Response.should_receive(:from_shell_executor). with(executor_mock). and_return(response) @deleter.delete_snapshot('snap_1').should == response end context 'when the gui is running' do before do Fission::Fusion.stub(:running?).and_return(true) end it 'should return an unsuccessful response if the vm is not running' do @running_response_mock.stub_as_successful false response = @deleter.delete_snapshot 'snap_1' error_message = 'A snapshot cannot be deleted when the GUI is running and the VM is not running.' response.should be_an_unsuccessful_response error_message end it 'should return an unsuccessful response if unable to determine if running' do @running_response_mock.stub_as_unsuccessful @deleter.delete_snapshot('snap_1').should be_an_unsuccessful_response end end end end fission-0.5.0/spec/fission/action/snapshot/creator_spec.rb0000644000076400007640000000617312511713252022746 0ustar pravipravirequire 'spec_helper' describe Fission::Action::Snapshot::Creator do describe 'create_snapshot' do before do @vm = Fission::VM.new 'foo' @conf_file_path = File.join @vm.path, 'foo.vmx' @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_response_mock = double('conf_file_response') @snapshots_response_mock = double('snapshots') @running_response_mock = double('running?') @running_response_mock.stub_as_successful true @conf_file_response_mock.stub_as_successful @conf_file_path @snapshots_response_mock.stub_as_successful [] @vm.stub(:exists?).and_return(true) @vm.stub(:snapshots).and_return(@snapshots_response_mock) @vm.stub(:running?).and_return(@running_response_mock) @vm.stub(:conf_file).and_return(@conf_file_response_mock) @creator = Fission::Action::Snapshot::Creator.new @vm end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @creator.create_snapshot('snap_1').should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if the vm is not running' do @running_response_mock.stub_as_successful false response = @creator.create_snapshot 'snap_1' error_message = 'The VM must be running in order to take a snapshot.' response.should be_an_unsuccessful_response error_message end it 'should return an unsuccessful response if unable to determine if running' do @running_response_mock.stub_as_unsuccessful @creator.create_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @creator.create_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return a response when creating the snapshot' do executor_mock = double('executor') response = double cmd = "#{@vmrun_cmd} snapshot " cmd << "'#{@conf_file_path}' \"bar\" 2>&1" executor_mock.should_receive(:execute).and_return(executor_mock) Fission::Action::ShellExecutor.should_receive(:new). with(cmd). and_return(executor_mock) Fission::Response.should_receive(:from_shell_executor). with(executor_mock). and_return(response) @creator.create_snapshot('bar').should == response end it 'should return an unsuccessful response if the snapshot name is a duplicate' do @snapshots_response_mock.stub_as_successful ['snap_1'] response = @creator.create_snapshot 'snap_1' response.should be_an_unsuccessful_response "There is already a snapshot named 'snap_1'." end it 'should return an unsuccessful response if there was a problem listing the existing snapshots' do @snapshots_response_mock.stub_as_unsuccessful @creator.create_snapshot('snap_1').should be_an_unsuccessful_response end end end fission-0.5.0/spec/fission/command_line_parser_spec.rb0000644000076400007640000002100512511713252022163 0ustar pravipravirequire 'spec_helper' describe Fission::CommandLineParser do before do @string_io = StringIO.new Fission::CommandLineParser.any_instance. stub(:ui). and_return(Fission::UI.new(@string_io)) end describe 'initialize' do it 'should set command to nil' do Fission::CommandLineParser.new.command.should be_nil end end describe 'parse' do context 'with no initial arguments' do it 'should output the usage info' do lambda { Fission::CommandLineParser.new([]).parse }.should raise_error SystemExit @string_io.string.should match /Usage/ end end context 'with -v or --version initial arguments' do ['-v', '--version'].each do |arg| it "should output the version with #{arg}" do lambda { Fission::CommandLineParser.new([arg]).parse }.should raise_error SystemExit @string_io.string.should match /#{Fission::VERSION}/ end end end context 'with -h or --help initial arguments' do ['-h', '--help'].each do |arg| it "should output the usage info with #{arg}" do lambda { Fission::CommandLineParser.new([arg]).parse }.should raise_error SystemExit @string_io.string.should match /Usage/ end end end context 'with an invalid sub command' do it 'should display the help' do lambda { Fission::CommandLineParser.new(['foo', 'bar']).parse }.should raise_error SystemExit @string_io.string.should match /Usage/ end end context 'with a valid sub command' do before do @cmd_mock = double('command', :summary => '') end [ ['clone'], ['delete'], ['snapshot', 'create'], ['snapshot', 'delete'], ['snapshot', 'list'], ['snapshot', 'revert'], ['start'], ['status'], ['stop'], ['suspend'] ].each do |command| it "should accept #{command}" do Fission::CommandLineParser.new(command).parse end it "should populate @command with an instance of the '#{command.join(' ')}' class" do klass = command.map { |c| c.capitalize }.join('') parser = Fission::CommandLineParser.new(command).parse parser.command.should be_an_instance_of Fission::Command.const_get klass end end context 'clone' do before do @cmd_mock.stub(:command_name).and_return('clone') Fission::Command::Clone.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::Clone.should_receive(:new). with(['foo', 'bar']) Fission::CommandLineParser.new(['clone', 'foo', 'bar']).parse end context 'with --start' do it 'should create the command with the start option' do Fission::Command::Clone.should_receive(:new). with(['foo', 'bar', '--start']) Fission::CommandLineParser.new(['clone', 'foo', 'bar', '--start']).parse end end end context 'delete' do before do @cmd_mock.stub(:command_name).and_return('delete') Fission::Command::Delete.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::Delete.should_receive(:new). with(['foo']) Fission::CommandLineParser.new(['delete', 'foo']).parse end context 'with --force' do it 'should create the command with the force option' do Fission::Command::Delete.should_receive(:new). with(['foo', '--force']) Fission::CommandLineParser.new(['delete', 'foo', '--force']).parse end end end context 'snapshot create' do before do @cmd_mock.stub(:command_name).and_return('snapshot create') Fission::Command::SnapshotCreate.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::SnapshotCreate.should_receive(:new). with(['foo', 'bar']) Fission::CommandLineParser.new(['snapshot', 'create', 'foo', 'bar']).parse end end context 'snapshot delete' do before do @cmd_mock.stub(:command_name).and_return('snapshot delete') Fission::Command::SnapshotDelete.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::SnapshotDelete.should_receive(:new). with(['foo', 'bar']) Fission::CommandLineParser.new(['snapshot', 'delete', 'foo', 'bar']).parse end end context 'snapshot list' do before do @cmd_mock.stub(:command_name).and_return('snapshot list') Fission::Command::SnapshotList.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::SnapshotList.should_receive(:new). with(['foo']) Fission::CommandLineParser.new(['snapshot', 'list', 'foo']).parse end end context 'snapshot revert' do before do @cmd_mock.stub(:command_name).and_return('snapshot revert') Fission::Command::SnapshotRevert.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::SnapshotRevert.should_receive(:new). with(['foo', 'bar']) Fission::CommandLineParser.new(['snapshot', 'revert', 'foo', 'bar']).parse end end context 'start' do before do @cmd_mock.stub(:command_name).and_return('start') Fission::Command::Start.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::Start.should_receive(:new). with(['foo']) Fission::CommandLineParser.new(['start', 'foo']).parse end context 'with --headless' do it 'should create the command with the force option' do Fission::Command::Start.should_receive(:new). with(['foo', '--headless']) Fission::CommandLineParser.new(['start', 'foo', '--headless']).parse end end end context 'status' do before do @cmd_mock.stub(:command_name).and_return('status') Fission::Command::Status.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::Status.should_receive(:new). with([]) Fission::CommandLineParser.new(['status']).parse end end context 'stop' do before do @cmd_mock.stub(:command_name).and_return('stop') Fission::Command::Stop.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::Stop.should_receive(:new). with(['foo']) Fission::CommandLineParser.new(['stop', 'foo']).parse end context 'with --force' do it 'should create the command with the force option' do Fission::Command::Stop.should_receive(:new). with(['foo', '--force']) Fission::CommandLineParser.new(['stop', 'foo', '--force']).parse end end end context 'suspend' do before do @cmd_mock.stub(:command_name).and_return('suspend') Fission::Command::Suspend.should_receive(:new).and_return(@cmd_mock) end it 'should create the command' do Fission::Command::Suspend.should_receive(:new). with(['foo']) Fission::CommandLineParser.new(['suspend', 'foo']).parse end context 'with --all' do it 'should create the command with the all option' do Fission::Command::Suspend.should_receive(:new). with(['--all']) Fission::CommandLineParser.new(['suspend', '--all']).parse end end end end end end fission-0.5.0/spec/fission/response_spec.rb0000644000076400007640000000532312511713252020025 0ustar pravipravirequire 'spec_helper' describe Fission::Response do describe 'initialize' do it 'should allow you to set the code' do Fission::Response.new(:code => 1).code.should == 1 end it 'should set the code to 1 if not provided' do Fission::Response.new.code.should == 1 end it 'should allow you to set the message' do Fission::Response.new(:message => 'foobar').message.should == 'foobar' end it 'should set the message to an empty string if not provided' do Fission::Response.new.message.should == '' end it 'should set the data to nil if not provided' do Fission::Response.new.data.should be_nil end end describe 'code' do it 'should allow you to set the code' do @response = Fission::Response.new @response.code = 4 @response.code.should == 4 end end describe 'successful?' do it 'should return true if the code is 0' do Fission::Response.new(:code => 0).successful?.should == true end it 'should return false if the code is not 0' do Fission::Response.new(:code => 1).successful?.should == false end end describe 'message' do it 'should allow you to set the message' do @response = Fission::Response.new @response.message = 'foobar' @response.message.should == 'foobar' end end describe 'data' do it 'should allow you to set the data' do @response = Fission::Response.new @response.data = [1, 2, 3] @response.data.should == [1, 2, 3] end end describe 'self.from_shell_executor' do before do @process_status = double('process status') end it 'should return a response object' do @process_status.stub(:exitstatus).and_return(0) executor = {'process_status' => @process_status} Fission::Response.from_shell_executor(executor).should be_a Fission::Response end it 'should set the code to the exit status' do @process_status.stub(:exitstatus).and_return(55) executor = {'process_status' => @process_status} Fission::Response.from_shell_executor(executor).code.should == 55 end it 'should set the message if the command was unsuccessful' do @process_status.stub(:exitstatus).and_return(55) executor = {'process_status' => @process_status, 'output' => 'foo'} Fission::Response.from_shell_executor(executor).message.should == 'foo' end it 'should not set the message if the command was successful' do @process_status.stub(:exitstatus).and_return(0) executor = {'process_status' => @process_status, 'output' => 'foo'} Fission::Response.from_shell_executor(executor).message.should == '' end end end fission-0.5.0/spec/fission/vm_configuration_spec.rb0000644000076400007640000001225012511713252021535 0ustar pravipravirequire 'spec_helper' describe Fission::VMConfiguration do before do @vm = Fission::VM.new 'foo' @conf_file_response_mock = double('conf_file_response') @conf_file_response_mock.stub_as_successful @conf_file_path end describe 'config_data' do before do @vm.stub(:exists?).and_return(true) @vm_config = Fission::VMConfiguration.new @vm @vm.stub(:conf_file).and_return(@conf_file_response_mock) end it "should return an unsuccessful response if the vm doesn't exist" do @vm.stub(:exists?).and_return(false) @vm_config.config_data.should be_an_unsuccessful_response 'VM does not exist' end it 'should return an unsuccessful response if unable to figure out the conf file' do @conf_file_response_mock.stub_as_unsuccessful @vm_config.config_data.should be_an_unsuccessful_response end context 'when the vm exists and the conf file can be found' do before do @conf_file_io = StringIO.new vmx_content = '.encoding = "UTF-8" config.version = "8" virtualHW.version = "7" scsi0.present = "TRUE" scsi0.virtualDev = "lsilogic" memsize = "384" scsi0:0.present = "TRUE" scsi0:0.fileName = "u10_04-000001.vmdk" ethernet0.present = "TRUE" ethernet0.connectionType = "nat" ethernet0.wakeOnPcktRcv = "FALSE" ethernet0.addressType = "generated" ethernet0.linkStatePropagation.enable = "TRUE" ehci.present = "TRUE" pciBridge4.virtualDev = "pcieRootPort" pciBridge4.functions = "8" vmci0.present = "TRUE" roamingVM.exitBehavior = "go" tools.syncTime = "TRUE" displayName = "u10_04" guestOS = "ubuntu" nvram = "u10_04.nvram" virtualHW.productCompatibility = "hosted" tools.upgrade.policy = "upgradeAtPowerCycle" extendedConfigFile = "u10_04.vmxf" serial0.present = "FALSE" usb.present = "FALSE" checkpoint.vmState = "u10_04.vmss" ethernet0.generatedAddress = "00:0c:29:c4:94:22" uuid.location = "56 4d 4b e9 1a bb 22 3a-b0 91 06 4e b4 c4 94 22" uuid.bios = "56 4d 4b e9 1a bb 22 3a-b0 91 06 4e b4 c4 94 22" cleanShutdown = "TRUE" scsi0:0.redo = "" scsi0.pciSlotNumber = "16" ethernet0.pciSlotNumber = "32" ethernet0.generatedAddressOffset = "0" vmci0.id = "-1262185438" tools.remindInstall = "TRUE"' @conf_file_io.string = vmx_content File.should_receive(:readlines).with(@conf_file_path). and_return(@conf_file_io.string.split(/$/)) end it 'should return a successful response' do @vm_config.config_data.should be_a_successful_response end it 'should return the data as a hash like object' do config = @vm_config.config_data config.data.should respond_to :keys config.data.should respond_to :values config.data.should respond_to :each_pair config.data.should respond_to :[] end it 'should return accurate data' do expected_data = { '.encoding' => 'UTF-8', 'config.version' => '8', 'virtualHW.version' => '7', 'scsi0.present' => 'TRUE', 'scsi0.virtualDev' => 'lsilogic', 'memsize' => '384', 'scsi0:0.present' => 'TRUE', 'scsi0:0.fileName' => 'u10_04-000001.vmdk', 'ethernet0.present' => 'TRUE', 'ethernet0.connectionType' => 'nat', 'ethernet0.wakeOnPcktRcv' => 'FALSE', 'ethernet0.addressType' => 'generated', 'ethernet0.linkStatePropagation.enable' => 'TRUE', 'ehci.present' => 'TRUE', 'pciBridge4.virtualDev' => 'pcieRootPort', 'pciBridge4.functions' => '8', 'vmci0.present' => 'TRUE', 'roamingVM.exitBehavior' => 'go', 'tools.syncTime' => 'TRUE', 'displayName' => 'u10_04', 'guestOS' => 'ubuntu', 'nvram' => 'u10_04.nvram', 'virtualHW.productCompatibility' => 'hosted', 'tools.upgrade.policy' => 'upgradeAtPowerCycle', 'extendedConfigFile' => 'u10_04.vmxf', 'serial0.present' => 'FALSE', 'usb.present' => 'FALSE', 'checkpoint.vmState' => 'u10_04.vmss', 'ethernet0.generatedAddress' => '00:0c:29:c4:94:22', 'uuid.location' => '56 4d 4b e9 1a bb 22 3a-b0 91 06 4e b4 c4 94 22', 'uuid.bios' => '56 4d 4b e9 1a bb 22 3a-b0 91 06 4e b4 c4 94 22', 'cleanShutdown' => 'TRUE', 'scsi0:0.redo' => '', 'scsi0.pciSlotNumber' => '16', 'ethernet0.pciSlotNumber' => '32', 'ethernet0.generatedAddressOffset' => '0', 'vmci0.id' => '-1262185438', 'tools.remindInstall' => 'TRUE' } config = @vm_config.config_data config.data.should == expected_data end end end end fission-0.5.0/spec/fission/command_helpers_spec.rb0000644000076400007640000000256012511713252021327 0ustar pravipravirequire 'spec_helper' describe Fission::CommandHelpers do include_context 'command_setup' before do @object = Object.new @object.extend Fission::CommandHelpers @object.class.stub(:help).and_return('foo help') end describe 'incorrect_arguments' do before do @object.stub(:command_name) @object.stub(:output) @object.stub(:output_and_exit) end it "should output the command's help text" do @object.stub(:command_name) @object.should_receive(:output).with(/foo help/) @object.incorrect_arguments end it 'should output that the argumets are incorrect and exit' do @object.stub(:command_name).and_return('delete') @object.should_receive(:output_and_exit). with('Incorrect arguments for delete command', 1) @object.incorrect_arguments end end describe 'parse arguments' do before do @object.stub(:option_parser).and_return(@object) end it 'should parse the arguments' do @object.stub :parse! @object.parse_arguments end it 'should output the error with help' do error = OptionParser::InvalidOption.new 'bar is invalid' @object.should_receive(:output).with(error) @object.should_receive(:output_and_exit).with(/foo help/, 1) @object.stub(:parse!).and_raise(error) @object.parse_arguments end end end fission-0.5.0/spec/fission/config_spec.rb0000644000076400007640000000605512511713252017437 0ustar pravipravirequire 'spec_helper' describe Fission::Config do describe "init" do before do FakeFS.activate! end after do FakeFS.deactivate! FakeFS::FileSystem.clear end it "should use the fusion default dir for vm_dir" do @config = Fission::Config.new @config.attributes['vm_dir'].should == File.expand_path('~/Documents/Virtual Machines.localized/') end it 'should use the fusion default for vmrun_bin' do @config = Fission::Config.new @config.attributes['vmrun_bin'].should == '/Library/Application Support/VMware Fusion/vmrun' end it 'should use the fusion default for plist_file' do @config = Fission::Config.new @config.attributes['plist_file'].should == File.expand_path('~/Library/Preferences/com.vmware.fusion.plist') end it 'should use the fusion default for the gui bin' do @config = Fission::Config.new @config.attributes['gui_bin'].should == File.expand_path('/Applications/VMware Fusion.app/Contents/MacOS/vmware') end it "should use the user specified dir in ~/.fissionrc" do home = File.expand_path('~') FileUtils.mkdir_p(home) File.open("#{home}/.fissionrc", 'w') do |f| f.puts YAML.dump({ 'vm_dir' => '/var/tmp/foo' }) end @config = Fission::Config.new @config.attributes['vm_dir'].should == '/var/tmp/foo' end it 'should use the user specified vmrun bin in ~/.fissionrc' do home = File.expand_path('~') FileUtils.mkdir_p(home) File.open("#{home}/.fissionrc", 'w') do |f| f.puts YAML.dump({ 'vmrun_bin' => '/var/tmp/vmrun_bin' }) end @config = Fission::Config.new @config.attributes['vmrun_bin'].should == '/var/tmp/vmrun_bin' end it 'should set vmrun_cmd' do @config = Fission::Config.new @config.attributes['vmrun_cmd'].should == "'/Library/Application Support/VMware Fusion/vmrun' -T fusion" end it 'should set the vmrun_cmd correctly if there is a user specified vmrun bin' do home = File.expand_path('~') FileUtils.mkdir_p(home) File.open("#{home}/.fissionrc", 'w') do |f| f.puts YAML.dump({ 'vmrun_bin' => '/var/tmp/vmrun_bin' }) end @config = Fission::Config.new @config.attributes['vmrun_cmd'].should == "'/var/tmp/vmrun_bin' -T fusion" end it 'should use the fusion default lease file' do @config = Fission::Config.new @config.attributes['lease_file'].should == '/var/db/vmware/vmnet-dhcpd-vmnet8.leases' end end describe '[]' do before do @config_items = { 'vmrun_bin' => '/foo/bar/vmrun', 'vmrun_cmd' => '/foo/bar/vmrun -T fusion', 'plist_file' => '/foo/bar/plist', 'gui_bin' => '/foo/bar/gui', 'vm_dir' => '/foo/bar/vms'} @config = Fission::Config.new @config.attributes = @config_items end it 'should return the value for specifed key' do @config_items.each_pair do |k, v| @config[k].should == v end end end end fission-0.5.0/spec/fission/command_spec.rb0000644000076400007640000000311712511713252017604 0ustar pravipravirequire 'spec_helper' describe Fission::Command do describe 'new' do it 'should set options variable as an open struct' do @command = Fission::Command.new @command.options.should be_kind_of OpenStruct end it 'should set the args variable' do @command = Fission::Command.new ['foo', 'bar'] @command.args.should == ['foo', 'bar'] end end describe 'command_name' do it 'should return the pretty command name' do cmd = Fission::Command.new cmd.command_name(Fission::Command::SnapshotList.new).should == 'snapshot list' end end describe 'help' do it 'should call option_parser on a new instance' do @new_instance_mock = double('new_instance') @new_instance_mock.should_receive(:option_parser).and_return('foo') Fission::Command.should_receive(:new).and_return(@new_instance_mock) Fission::Command.help.should == 'foo' end end describe 'summary' do it "should raise an exception that it's not implemented" do lambda { Fission::Command.new.summary }.should raise_error NotImplementedError end end describe 'ui' do it 'should load a ui object' do Fission::Command.new.ui.should be_a Fission::UI end [:output, :output_and_exit, :output_printf].each do |item| it "should delegate '#{item.to_s}' to the ui instance" do @ui_mock = double('ui') @ui_mock.should_receive(item) Fission::UI.stub(:new).and_return(@ui_mock) @cmd_instance = Fission::Command.new @cmd_instance.send item, 'foo' end end end end fission-0.5.0/spec/fission/vm_spec.rb0000644000076400007640000007313312511713252016615 0ustar pravipravirequire 'spec_helper' describe Fission::VM do before do @vm = Fission::VM.new('foo') @conf_file_path = File.join(@vm.path, 'foo.vmx') @vmrun_cmd = Fission.config['vmrun_cmd'] @conf_file_response_mock = double('conf_file_response') end describe 'new' do it 'should set the vm name' do Fission::VM.new('foo').name.should == 'foo' end end describe 'delete' do before do @vm_deleter = double('vm deleter') @delete_response_mock = double('vm delete response') Fission::Action::VM::Deleter.stub(:new).and_return(@vm_deleter) @vm_deleter.should_receive(:delete). and_return(@delete_response_mock) end it 'should return an unsuccessful response when unable to delete the vm' do @delete_response_mock.stub_as_unsuccessful @vm.delete.should be_an_unsuccessful_response end it 'should return a successful response when deleting' do @delete_response_mock.stub_as_successful @vm.delete.should be_a_successful_response end end describe 'start' do before do @vm_starter = double('vm starter') @start_response_mock = double('vm start response') Fission::Action::VM::Starter.stub(:new).and_return(@vm_starter) end it 'should return an unsuccessful response when unable to start the vm' do @vm_starter.should_receive(:start). and_return(@start_response_mock) @start_response_mock.stub_as_unsuccessful @vm.start.should be_an_unsuccessful_response end it 'should return a successful response when starting headless' do @vm_starter.should_receive(:start). with(:headless => true). and_return(@start_response_mock) @start_response_mock.stub_as_successful @vm.start(:headless => true).should be_a_successful_response end it 'should return a successful response when starting' do @vm_starter.should_receive(:start). and_return(@start_response_mock) @start_response_mock.stub_as_successful @vm.start.should be_a_successful_response end end describe 'stop' do before do @vm_stopper = double('vm stopper') @stop_response_mock = double('vm stop response') Fission::Action::VM::Stopper.stub(:new).and_return(@vm_stopper) end it 'should return a successful response when stopping' do @vm_stopper.should_receive(:stop). and_return(@stop_response_mock) @stop_response_mock.stub_as_successful @vm.stop.should be_a_successful_response end it 'should return an unsuccessful response when unable to stop the vm' do @vm_stopper.should_receive(:stop). and_return(@stop_response_mock) @stop_response_mock.stub_as_unsuccessful @vm.stop.should be_an_unsuccessful_response end it 'should return a successful response when stopping hard' do @vm_stopper.should_receive(:stop). with(:hard => true). and_return(@stop_response_mock) @stop_response_mock.stub_as_successful @vm.stop(:hard => true).should be_a_successful_response end end describe 'suspend' do before do @vm_suspender = double('vm suspender') @suspend_response_mock = double('vm suspend response') Fission::Action::VM::Suspender.stub(:new).and_return(@vm_suspender) @vm_suspender.should_receive(:suspend). and_return(@suspend_response_mock) end it 'should return a successful response when suspending' do @suspend_response_mock.stub_as_successful @vm.suspend.should be_a_successful_response end it 'should return an unsuccessful response when unable to suspend the vm' do @suspend_response_mock.stub_as_unsuccessful @vm.suspend.should be_an_unsuccessful_response end end describe 'snapshots' do before do @snapshot_lister_mock = double('snapshot lister') @snapshots_response_mock = double('snapshots mock') Fission::Action::Snapshot::Lister.stub(:new).and_return(@snapshot_lister_mock) @snapshot_lister_mock.should_receive(:snapshots). and_return(@snapshots_response_mock) end it "should return an unsuccessful repsonse when unable to list the snapshots" do @snapshots_response_mock.stub_as_unsuccessful @vm.snapshots.should be_an_unsuccessful_response end it 'should return a successful response with the list of snapshots' do @snapshots_response_mock.stub_as_successful ['snap_1', 'snap_2'] response = @vm.snapshots response.should be_a_successful_response response.data.should == ['snap_1', 'snap_2'] end end describe 'create_snapshot' do before do @snapshot_creator_mock = double('snapshot creator') @snapshot_create_response_mock = double('snapshot create response') Fission::Action::Snapshot::Creator.stub(:new).and_return(@snapshot_creator_mock) @snapshot_creator_mock.should_receive(:create_snapshot). with('snap_1'). and_return(@snapshot_create_response_mock) end it 'should return an unsuccessful response when unable to create the snapshot' do @snapshot_create_response_mock.stub_as_unsuccessful @vm.create_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return a successful response when creating the snapshot' do @snapshot_create_response_mock.stub_as_successful @vm.create_snapshot('snap_1').should be_a_successful_response end end describe 'delete_snapshot' do before do @snapshot_deleter_mock = double('snapshot deleter') @snapshot_delete_response_mock = double('snapshot delete response') Fission::Action::Snapshot::Deleter.stub(:new). and_return(@snapshot_deleter_mock) @snapshot_deleter_mock.should_receive(:delete_snapshot). with('snap_1'). and_return(@snapshot_delete_response_mock) end it 'should return an unsuccessful response when unable to delete the snapshot' do @snapshot_delete_response_mock.stub_as_unsuccessful @vm.delete_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return a successful response when deleteing the snapshot' do @snapshot_delete_response_mock.stub_as_successful @vm.delete_snapshot('snap_1').should be_a_successful_response end end describe 'revert_to_snapshot' do before do @snapshot_reverter_mock = double('snapshot reverter') @snapshot_revert_response_mock = 'snapshot revert response' Fission::Action::Snapshot::Reverter.stub(:new). and_return(@snapshot_reverter_mock) @snapshot_reverter_mock.should_receive(:revert_to_snapshot). with('snap_1'). and_return(@snapshot_revert_response_mock) end it 'should return an unsuccessful response when unable to revert the snapshot' do @snapshot_revert_response_mock.stub_as_unsuccessful @vm.revert_to_snapshot('snap_1').should be_an_unsuccessful_response end it 'should return a successful response when reverting the snapshot' do @snapshot_revert_response_mock.stub_as_successful @vm.revert_to_snapshot('snap_1').should be_a_successful_response end end describe 'exists?' do before do @conf_file_response = double('exists') @vm.stub(:conf_file).and_return(@conf_file_response) end it 'should return true if the VM exists' do @conf_file_response.stub_as_successful '/vms/foo/foo.vmx' @vm.exists?.should == true end it 'should return false if the VM does not exist' do @conf_file_response.stub_as_unsuccessful @vm.exists?.should == false end end describe 'hardware_info' do before do @vm_config_data_response_mock = double('vm config data response') @vm.stub(:conf_file_data).and_return(@vm_config_data_response_mock) @config_data = { 'numvcpus' => '2', 'replay.supported' => "TRUE", 'replay.filename' => '', 'memsize' => '2048', 'scsi0:0.redo' => '' } end context 'when successful getting the vm config data' do before do @vm_config_data_response_mock.stub_as_successful @config_data end context 'when the number of cpus is not specified in the conf file' do before do @config_data.delete 'numvcpus' end it 'should return a successful response with a single cpu' do response = @vm.hardware_info response.should be_a_successful_response response.data.should have_key 'cpus' response.data['cpus'].should == 1 end end it 'should return a successful response with the number of cpus' do response = @vm.hardware_info response.should be_a_successful_response response.data.should have_key 'cpus' response.data['cpus'].should == 2 end it 'should return a successful response with the amount of memory' do response = @vm.hardware_info response.should be_a_successful_response response.data.should have_key 'memory' response.data['memory'].should == 2048 end end context 'when unsuccessfully getting the vm config data' do it 'should return an unsuccessful response' do @vm_config_data_response_mock.stub_as_unsuccessful @vm.hardware_info.should be_an_unsuccessful_response end end end describe 'mac_addresses' do before do @network_info_mock = double('network_info') @vm.should_receive(:network_info).and_return(@network_info_mock) end it 'should return a successful response with the list of mac addresses' do network_data = { 'ethernet0' => { 'mac_address' => '00:0c:29:1d:6a:64', 'ip_address' => '127.0.0.1' }, 'ethernet1' => { 'mac_address' => '00:0c:29:1d:6a:75', 'ip_address' => '127.0.0.2' } } @network_info_mock.stub_as_successful network_data response = @vm.mac_addresses response.should be_a_successful_response response.data.should =~ ['00:0c:29:1d:6a:64', '00:0c:29:1d:6a:75'] end it 'should return a successful response with an empty list if no mac addresses were found' do @network_info_mock.stub_as_successful Hash.new response = @vm.mac_addresses response.should be_a_successful_response response.data.should == [] end it 'should return an unsuccessful response if there was an error getting the mac addresses' do @network_info_mock.stub_as_unsuccessful response = @vm.mac_addresses response.should be_an_unsuccessful_response response.data.should be_nil end end describe 'network_info' do before do @lease_1_response_mock = double('lease_1_response') @lease_2_response_mock = double('lease_1_response') @vm_config_data_response_mock = double('vm config data response') @vm.stub(:conf_file_data).and_return(@vm_config_data_response_mock) @config_data = { 'ide1:0.deviceType' => 'cdrom-image', 'ethernet0.present' => 'TRUE', 'ethernet1.address' => '00:0c:29:1d:6a:75', 'ethernet0.connectionType' => 'nat', 'ethernet0.generatedAddress' => '00:0c:29:1d:6a:64', 'ethernet0.virtualDev' => 'e1000', 'ethernet0.wakeOnPcktRcv' => 'FALSE', 'ethernet0.addressType' => 'generated', 'ethernet0.linkStatePropagatio.enable' => 'TRUE', 'ethernet0.generatedAddressenable' => 'TRUE', 'ethernet1.generatedAddressenable' => 'TRUE' } end context 'when successful getting the vm config data' do before do @vm_config_data_response_mock.stub_as_successful @config_data end it 'should return a successful response with the list of interfaces, macs, and ips' do @lease_1 = Fission::Lease.new :ip_address => '127.0.0.1', :mac_address => '00:0c:29:1d:6a:64' @lease_1_response_mock.stub_as_successful @lease_1 @lease_2 = Fission::Lease.new :ip_address => '127.0.0.2', :mac_address => '00:0c:29:1d:6a:75' @lease_2_response_mock.stub_as_successful @lease_2 Fission::Lease.should_receive(:find_by_mac_address). with('00:0c:29:1d:6a:64'). and_return(@lease_1_response_mock) Fission::Lease.should_receive(:find_by_mac_address). with('00:0c:29:1d:6a:75'). and_return(@lease_2_response_mock) response = @vm.network_info response.should be_a_successful_response response.data.should == { 'ethernet0' => { 'mac_address' => '00:0c:29:1d:6a:64', 'ip_address' => '127.0.0.1' }, 'ethernet1' => { 'mac_address' => '00:0c:29:1d:6a:75', 'ip_address' => '127.0.0.2' } } end it 'should return a successful response with an empty list if there are no macs' do @config_data.delete 'ethernet0.generatedAddress' @config_data.delete 'ethernet1.address' response = @vm.network_info response.should be_a_successful_response response.data.should == {} end it 'should return a successful response without ip addresses if none were found' do @lease_1_response_mock.stub_as_successful nil @lease_2_response_mock.stub_as_successful nil Fission::Lease.should_receive(:find_by_mac_address). with('00:0c:29:1d:6a:64'). and_return(@lease_1_response_mock) Fission::Lease.should_receive(:find_by_mac_address). with('00:0c:29:1d:6a:75'). and_return(@lease_2_response_mock) response = @vm.network_info response.should be_a_successful_response response.data.should == { 'ethernet0' => { 'mac_address' => '00:0c:29:1d:6a:64', 'ip_address' => nil }, 'ethernet1' => { 'mac_address' => '00:0c:29:1d:6a:75', 'ip_address' => nil } } end context 'when unsuccessful getting the ip info' do it 'should return an unsuccessful response if there was an error getting the ip information' do @lease_1_response_mock.stub_as_unsuccessful @lease_2_response_mock.stub_as_successful nil Fission::Lease.should_receive(:find_by_mac_address). with('00:0c:29:1d:6a:64'). and_return(@lease_1_response_mock) Fission::Lease.should_receive(:find_by_mac_address). with('00:0c:29:1d:6a:75'). and_return(@lease_2_response_mock) @vm.network_info.should be_an_unsuccessful_response end end end context 'when unsuccessfully getting the vm config data' do it 'should return an unsuccessful response' do @vm_config_data_response_mock.stub_as_unsuccessful @vm.guestos.should be_an_unsuccessful_response end end end describe 'guestos' do before do @vm_config_data_response_mock = double('vm config data response') @vm.stub(:conf_file_data).and_return(@vm_config_data_response_mock) @config_data = { 'cleanShutdown' => 'TRUE', 'guestOS' => 'debian5', 'replay.filename' => '', 'scsi0:0.redo' => '' } end context 'when successful getting the vm config data' do it 'should return a successful response with a string when a guestos is defined' do @vm_config_data_response_mock.stub_as_successful @config_data response = @vm.guestos response.should be_a_successful_response response.data.should == 'debian5' end it 'should return a successful response with an empty string if guestos is not set' do @config_data.delete 'guestOS' @vm_config_data_response_mock.stub_as_successful @config_data response = @vm.guestos response.should be_a_successful_response response.data.should == '' end end context 'when unsuccessfully getting the vm config data' do it 'should return an unsuccessful response' do @vm_config_data_response_mock.stub_as_unsuccessful @vm.guestos.should be_an_unsuccessful_response end end end describe 'uuids' do before do @vm_config_data_response_mock = double('vm config data response') @vm.stub(:conf_file_data).and_return(@vm_config_data_response_mock) @config_data = { 'uuid.location' => '56 4d d8 9c f8 ec 95 73-2e ea a0 f3 7a 1d 6f c8', 'uuid.bios' => '56 4d d8 9c f8 ec 95 73-2e ea a0 f3 7a 1d 6f c8', 'checkpoint.vmState' => '', 'cleanShutdown' => 'TRUE', 'replay.supported' => "TRUE", 'replay.filename' => '', 'scsi0:0.redo' =>'' } end context 'when successful getting the vm config data' do it 'should return a successful response with a hash when uuids are defined' do @vm_config_data_response_mock.stub_as_successful @config_data response = @vm.uuids response.should be_a_successful_response response.data.should == { 'bios' => '56 4d d8 9c f8 ec 95 73-2e ea a0 f3 7a 1d 6f c8', 'location' => '56 4d d8 9c f8 ec 95 73-2e ea a0 f3 7a 1d 6f c8' } end it 'should return a successful response with empty hash if no uuids are defined' do ['location', 'bios'].each { |i| @config_data.delete "uuid.#{i}" } @vm_config_data_response_mock.stub_as_successful @config_data response = @vm.uuids response.should be_a_successful_response response.data.should == {} end end context 'when unsuccessfully getting the vm config data' do it 'should return an unsuccessful response' do @vm_config_data_response_mock.stub_as_unsuccessful @vm.uuids.should be_an_unsuccessful_response end end end describe 'path' do it 'should return the path of the VM' do vm_path = File.join(Fission.config['vm_dir'], 'foo.vmwarevm').gsub '\\', '' Fission::VM.new('foo').path.should == vm_path end end describe 'state' do before do @vm_1 = Fission::VM.new 'foo' @vm_2 = Fission::VM.new 'bar' @all_running_response_mock = double('all_running') @suspended_response_mock = double('suspended') Fission::VM.stub(:all_running).and_return(@all_running_response_mock) @all_running_response_mock.stub_as_successful [@vm_2] end it "should return a successful response and 'not running' when the VM is off" do response = @vm.state response.should be_a_successful_response response.data.should == 'not running' end it "should return a successful resopnse and 'running' when the VM is running" do @all_running_response_mock.stub_as_successful [@vm_1, @vm_2] response = @vm.state response.should be_a_successful_response response.data.should == 'running' end it "should return a successful response and 'suspended' when the VM is suspended" do @suspended_response_mock.stub_as_successful true @vm.stub(:suspended?).and_return(@suspended_response_mock) response = @vm.state response.should be_a_successful_response response.data.should == 'suspended' end it 'should return an unsuccessful response if there was an error getting the running VMs' do @all_running_response_mock.stub_as_unsuccessful @vm.state.should be_an_unsuccessful_response end it 'should return an unsuccessful repsonse if there was an error determining if the VM is suspended' do @suspended_response_mock.stub_as_unsuccessful @vm.stub(:suspended?).and_return(@suspended_response_mock) @vm.state.should be_an_unsuccessful_response end end describe 'running?' do before do @all_running_response_mock = double('all_running') Fission::VM.stub(:all_running).and_return(@all_running_response_mock) end it 'should return a successful response and false when the vm is not running' do @all_running_response_mock.stub_as_successful [] response = @vm.running? response.should be_a_successful_response response.data.should == false end it 'should return a successful response and true if the vm is running' do @all_running_response_mock.stub_as_successful [Fission::VM.new('foo')] response = @vm.running? response.should be_a_successful_response response.data.should == true end it 'should return an unsuccessful repsponse if there is an error getting the list of running vms' do @all_running_response_mock.stub_as_unsuccessful @vm.running?.should be_an_unsuccessful_response end end describe 'suspend_file_exists?' do before do FakeFS.activate! FileUtils.mkdir_p @vm.path end after do FakeFS.deactivate! FakeFS::FileSystem.clear end it 'should return true if the suspend file exists' do FileUtils.touch(File.join(@vm.path, "#{@vm.name}.vmem")) @vm.suspend_file_exists?.should == true end it 'should return false if the suspend file does not exist' do @vm.suspend_file_exists?.should == false end end describe 'suspended?' do before do @running_response_mock = double('running?') @vm.stub(:running?).and_return(@running_response_mock) end describe 'when the vm is not running' do before do @running_response_mock.stub_as_successful false end it 'should return a successful response and true if a .vmem file exists in the vm dir' do @vm.stub(:suspend_file_exists?).and_return(true) response = @vm.suspended? response.should be_a_successful_response response.data.should == true end it 'should return a successful response and false if a .vmem file is not found in the vm dir' do @vm.stub(:suspend_file_exists?).and_return(false) response = @vm.suspended? response.should be_a_successful_response response.data.should == false end end it 'should return a successful response and false if the vm is running' do @running_response_mock.stub_as_successful true response = @vm.suspended? response.should be_a_successful_response response.data.should == false end it 'should return an unsuccessful repsponse if there is an error getting the list of running vms' do @running_response_mock.stub_as_unsuccessful @vm.suspended?.should be_an_unsuccessful_response end end describe 'conf_file_data' do before do @vm_config_mock = double('vm config') @vm_config_response_mock = double('vm config response') Fission::VMConfiguration.should_receive(:new).with(@vm). and_return(@vm_config_mock) end it 'should return a successful response with the data' do @vm_config_response_mock.stub_as_successful({ 'numvcpus' => '2' }) @vm_config_mock.should_receive(:config_data). and_return(@vm_config_response_mock) config_data = @vm.conf_file_data config_data.should be_a_successful_response config_data.data.should == { 'numvcpus' => '2' } end it 'should return an unsuccessful response' do @vm_config_mock.should_receive(:config_data). and_return(@vm_config_response_mock) @vm_config_response_mock.stub_as_unsuccessful @vm.conf_file_data.should be_an_unsuccessful_response end end describe 'conf_file' do before do FakeFS.activate! @vm_root_dir = Fission::VM.new('foo').path FileUtils.mkdir_p(@vm_root_dir) end after do FakeFS.deactivate! FakeFS::FileSystem.clear end it 'should return a successful response with the path to the conf file' do file_path = File.join(@vm_root_dir, 'foo.vmx') FileUtils.touch(file_path) response = Fission::VM.new('foo').conf_file response.should be_a_successful_response response.data.should == file_path end it 'should return an unsuccessful response with an error if no vmx file was found' do response = Fission::VM.new('foo').conf_file response.successful?.should == false response.message.should match /Unable to find a config file for VM 'foo' \(in '#{File.join(@vm_root_dir, '\*\.vmx')}'\)/m end describe 'when the VM name and conf file name do not match' do it 'should return the path to the conf file' do file_path = File.join(@vm_root_dir, 'bar.vmx') FileUtils.touch(file_path) response = Fission::VM.new('foo').conf_file response.should be_a_successful_response response.data.should == file_path end end describe 'if multiple vmx files are found' do it 'should use return a successful response with the conf file which matches the VM name if it exists' do ['foo.vmx', 'bar.vmx'].each do |file| FileUtils.touch(File.join(@vm_root_dir, file)) end response = Fission::VM.new('foo').conf_file response.should be_a_successful_response response.data.should == File.join(@vm_root_dir, 'foo.vmx') end it 'should return an unsuccessful object if none of the conf files matches the VM name' do ['bar.vmx', 'baz.vmx'].each do |file| FileUtils.touch(File.join(@vm_root_dir, file)) end Fission::VM.new('foo').conf_file response = Fission::VM.new('foo').conf_file response.successful?.should == false error_regex = /Multiple config files found for VM 'foo' \('bar\.vmx', 'baz\.vmx' in '#{@vm_root_dir}'/m response.message.should match error_regex end end end describe "self.all" do before do @lister = double('lister') @all_response_mock = double('all response') Fission::Action::VM::Lister.stub(:new).and_return(@lister) @lister.should_receive(:all). and_return(@all_response_mock) end it 'should return an unsuccessful response when unable to delete the vm' do @all_response_mock.stub_as_unsuccessful Fission::VM.all.should be_an_unsuccessful_response end it 'should return a successful response when deleting' do @all_response_mock.stub_as_successful Fission::VM.all.should be_a_successful_response end end describe 'self.all_running' do before do @lister = double('lister') @all_running_response_mock = double('all running response') Fission::Action::VM::Lister.stub(:new).and_return(@lister) @lister.should_receive(:all_running). and_return(@all_running_response_mock) end it 'should return an unsuccessful response when unable to delete the vm' do @all_running_response_mock.stub_as_unsuccessful Fission::VM.all_running.should be_an_unsuccessful_response end it 'should return a successful response when deleting' do @all_running_response_mock.stub_as_successful Fission::VM.all_running.should be_a_successful_response end end describe "self.clone" do before do @vm_1 = double('vm 1') @vm_2 = double('vm 2') @vm_cloner = double('vm cloner') @clone_response_mock = double('vm clone response') Fission::Action::VM::Cloner.should_receive(:new). with(@vm_1, @vm_2). and_return(@vm_cloner) Fission::VM.should_receive(:new).with('vm_1').and_return(@vm_1) Fission::VM.should_receive(:new).with('vm_2').and_return(@vm_2) @vm_cloner.should_receive(:clone). and_return(@clone_response_mock) end it 'should return an unsuccessful response when unable to clone the vm' do @clone_response_mock.stub_as_unsuccessful Fission::VM.clone('vm_1', 'vm_2').should be_an_unsuccessful_response end it 'should return a successful response when cloning' do @clone_response_mock.stub_as_successful Fission::VM.clone('vm_1', 'vm_2').should be_a_successful_response end end describe 'self.all_with_status' do before do @lister = double('lister') @all_status_response_mock = double('all status response') Fission::Action::VM::Lister.stub(:new).and_return(@lister) @lister.should_receive(:all_with_status). and_return(@all_status_response_mock) end it 'should return an unsuccessful response when unable to delete the vm' do @all_status_response_mock.stub_as_unsuccessful Fission::VM.all_with_status.should be_an_unsuccessful_response end it 'should return a successful response when deleting' do @all_status_response_mock.stub_as_successful Fission::VM.all_with_status.should be_a_successful_response end end end fission-0.5.0/spec/fission/command/0000755000076400007640000000000012511713252016243 5ustar pravipravifission-0.5.0/spec/fission/command/snapshot_revert_spec.rb0000644000076400007640000000446312511713252023037 0ustar pravipravirequire 'spec_helper' describe Fission::Command::SnapshotRevert do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @snap_revert_response_mock = double('snap_revert_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::SnapshotRevert.new.command_name.should == 'snapshot revert' end end describe 'execute' do subject { Fission::Command::SnapshotRevert } [ [], ['foo'], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'snapshot revert' end it "should output an error and the help when no snapshot name is passed in" do Fission::Command::SnapshotRevert.should_receive(:help) command = Fission::Command::SnapshotRevert.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Incorrect arguments for snapshot revert command/ end it 'should revert to the snapshot with the provided name' do @snap_revert_response_mock.stub_as_successful @vm_mock.should_receive(:revert_to_snapshot).with('snap_1'). and_return(@snap_revert_response_mock) command = Fission::Command::SnapshotRevert.new @target_vm << 'snap_1' command.execute @string_io.string.should match /Reverting to snapshot 'snap_1'/ @string_io.string.should match /Reverted to snapshot 'snap_1'/ end it 'should output an error and exit if there was an error reverting to the snapshot' do @snap_revert_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:revert_to_snapshot).with('snap_1'). and_return(@snap_revert_response_mock) command = Fission::Command::SnapshotRevert.new @target_vm << 'snap_1' lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Reverting to snapshot 'snap_1'/ @string_io.string.should match /There was an error reverting to the snapshot.+it blew up.+/m end end describe 'help' do it 'should output info for this command' do output = Fission::Command::SnapshotRevert.help output.should match /fission snapshot revert TARGET_VM TARGET_SNAPSHOT/ end end end fission-0.5.0/spec/fission/command/stop_spec.rb0000644000076400007640000000323012511713252020565 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Stop do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @stop_response_mock = double('stop_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Stop.new.command_name.should == 'stop' end end describe 'execute' do subject { Fission::Command::Stop } [ [], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'stop' end it 'should stop the vm' do @stop_response_mock.should_receive(:successful?).and_return(true) @vm_mock.should_receive(:stop).and_return(@stop_response_mock) command = Fission::Command::Stop.new @target_vm command.execute @string_io.string.should match /Stopping '#{@target_vm.first}'/ @string_io.string.should match /VM '#{@target_vm.first}' stopped/ end it 'should output an error and exit if there was an error stopping the vm' do @stop_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:stop).and_return(@stop_response_mock) command = Fission::Command::Stop.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Stopping '#{@target_vm.first}'/ @string_io.string.should match /There was an error stopping the VM.+it blew up.+/m end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Stop.help output.should match /fission stop TARGET_VM/ end end end fission-0.5.0/spec/fission/command/info_spec.rb0000644000076400007640000001032712511713252020540 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Info do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @network_info_response_mock = double('network_info_response') @hardware_info_response_mock = double('hardware_info_response') @guest_os_response_mock = double('guest_os_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Info.new.command_name.should == 'info' end end describe 'execute' do before do @vm_mock.stub(:network_info).and_return(@network_info_response_mock) @vm_mock.stub(:hardware_info).and_return(@hardware_info_response_mock) @vm_mock.stub(:guestos).and_return(@guest_os_response_mock) @network_info = { 'ethernet0' => { 'mac_address' => '00:11:22:33:AA:BB', 'ip_address' => '192.168.1.10' }, 'ethernet1' => { 'mac_address' => '00:11:22:33:AA:BB', 'ip_address' => '192.168.1.10' } } @hardware_info_response_mock.stub_as_successful Hash.new @network_info_response_mock.stub_as_successful Hash.new @guest_os_response_mock.stub_as_successful 'debian5' end subject { Fission::Command::Info } [ [], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'info' end it 'should output the vm name' do command = Fission::Command::Info.new @target_vm command.execute @string_io.string.should match /foo/ end it 'should output the os' do command = Fission::Command::Info.new @target_vm command.execute @string_io.string.should match /os: debian5/ end it 'should output that the os is unknown if applicable' do @guest_os_response_mock.stub_as_successful '' command = Fission::Command::Info.new @target_vm command.execute @string_io.string.should match /os: unknown/ end it 'should output an error and exit if there was an error getting the os info' do @guest_os_response_mock.stub_as_unsuccessful command = Fission::Command::Info.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error getting the OS info.+it blew up.+/m end it 'should output the number of cpus' do hardware_info = { 'cpus' => 2} @hardware_info_response_mock.stub_as_successful hardware_info command = Fission::Command::Info.new @target_vm command.execute @string_io.string.should match /cpus\: 2/ end it 'should output the amount of memory' do hardware_info = { 'memory' => 2048} @hardware_info_response_mock.stub_as_successful hardware_info command = Fission::Command::Info.new @target_vm command.execute @string_io.string.should match /memory\: 2048/ end it 'should output an error and exit if there was an error getting the hardware info' do @hardware_info_response_mock.stub_as_unsuccessful command = Fission::Command::Info.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error getting the hardware info.+it blew up.+/m end it 'should output the network info' do @network_info_response_mock.stub_as_successful @network_info command = Fission::Command::Info.new @target_vm command.execute @string_io.string.should match /ethernet0 mac address: 00:11:22:33:AA:BB/ @string_io.string.should match /ethernet0 ip address: 192\.168\.1\.10/ end it 'should output an error and exit if there was an error getting the network info' do @network_info_response_mock.stub_as_unsuccessful command = Fission::Command::Info.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error getting the network info.+it blew up.+/m end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Info.help output.should match /fission info TARGET_VM/ end end end fission-0.5.0/spec/fission/command/status_spec.rb0000644000076400007640000000360512511713252021131 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Status do include_context 'command_setup' before do @vms_status = { 'foo' => 'running', 'bar' => 'suspended', 'baz' => 'not running' } @all_status_response_mock = double('response') end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Status.new.command_name.should == 'status' end end describe 'execute' do subject { Fission::Command::Status } [ ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'status' end describe 'when successful' do before do @all_status_response_mock.stub_as_successful @vms_status Fission::VM.should_receive(:all_with_status). and_return(@all_status_response_mock) end it 'should output the VMs and their status' do command = Fission::Command::Status.new command.execute @string_io.string.should match /foo.+\[running\]/ @string_io.string.should match /bar.+\[suspended\]/ @string_io.string.should match /baz.+\[not running\]/ end end describe 'when unsuccessful' do before do @all_status_response_mock.stub_as_unsuccessful Fission::VM.should_receive(:all_with_status). and_return(@all_status_response_mock) end it 'should output an error and exit if there was an error getting the list of running VMs' do command = Fission::Command::Status.new lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error getting the status of the VMs.+it blew up/m end end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Status.help output.should match /fission status/ end end end fission-0.5.0/spec/fission/command/snapshot_create_spec.rb0000644000076400007640000000444712511713252022775 0ustar pravipravirequire 'spec_helper' describe Fission::Command::SnapshotCreate do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @snap_create_response_mock = double('snap_create_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::SnapshotCreate.new.command_name.should == 'snapshot create' end end describe 'execute' do subject { Fission::Command::SnapshotCreate } [ [], ['foo'], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'snapshot create' end it "should output an error and the help when no snapshot name is passed in" do Fission::Command::SnapshotCreate.should_receive(:help) command = Fission::Command::SnapshotCreate.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Incorrect arguments for snapshot create command/ end it 'should create a new snapshot with the provided name' do @snap_create_response_mock.stub_as_successful [] @vm_mock.should_receive(:create_snapshot). with('snap_1'). and_return(@snap_create_response_mock) command = Fission::Command::SnapshotCreate.new @target_vm << 'snap_1' command.execute @string_io.string.should match /Creating snapshot/ @string_io.string.should match /Snapshot 'snap_1' created/ end it 'should output an error and exit if there was an error creating the snapshot' do @snap_create_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:create_snapshot). with('snap_1'). and_return(@snap_create_response_mock) command = Fission::Command::SnapshotCreate.new @target_vm << 'snap_1' lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Creating snapshot/ @string_io.string.should match /There was an error creating the snapshot.+it blew up.+/m end end describe 'help' do it 'should output info for this command' do output = Fission::Command::SnapshotCreate.help output.should match /fission snapshot create TARGET_VM SNAPSHOT_NAME/ end end end fission-0.5.0/spec/fission/command/snapshot_delete_spec.rb0000644000076400007640000000444712511713252022774 0ustar pravipravirequire 'spec_helper' describe Fission::Command::SnapshotDelete do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @snap_delete_response_mock = double('snap_delete_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::SnapshotDelete.new.command_name.should == 'snapshot delete' end end describe 'execute' do subject { Fission::Command::SnapshotDelete } [ [], ['foo'], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'snapshot delete' end it "should output an error and the help when no snapshot name is passed in" do Fission::Command::SnapshotDelete.should_receive(:help) command = Fission::Command::SnapshotDelete.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Incorrect arguments for snapshot delete command/ end it 'should delete a new snapshot with the provided name' do @snap_delete_response_mock.stub_as_successful [] @vm_mock.should_receive(:delete_snapshot). with('snap_1'). and_return(@snap_delete_response_mock) command = Fission::Command::SnapshotDelete.new @target_vm << 'snap_1' command.execute @string_io.string.should match /Deleting snapshot/ @string_io.string.should match /Snapshot 'snap_1' deleted/ end it 'should output an error and exit if there was an error creating the snapshot' do @snap_delete_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:delete_snapshot). with('snap_1'). and_return(@snap_delete_response_mock) command = Fission::Command::SnapshotDelete.new @target_vm << 'snap_1' lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Deleting snapshot/ @string_io.string.should match /There was an error deleting the snapshot.+it blew up.+/m end end describe 'help' do it 'should output info for this command' do output = Fission::Command::SnapshotDelete.help output.should match /fission snapshot delete TARGET_VM SNAPSHOT_NAME/ end end end fission-0.5.0/spec/fission/command/delete_spec.rb0000644000076400007640000001066712511713252021056 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Delete do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @delete_response_mock = double('delete_response') @running_response_mock = double('running?') @vm_mock.stub(:name).and_return(@target_vm.first) @vm_mock.stub(:running?).and_return(@running_response_mock) @running_response_mock.stub_as_successful false Fission::Fusion.stub(:running?).and_return(false) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Delete.new.command_name.should == 'delete' end end describe "execute" do subject { Fission::Command::Delete } [ [], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'delete' end it "should try to delete the vm" do @delete_response_mock.stub_as_successful @vm_mock.should_receive(:delete).and_return(@delete_response_mock) Fission::Fusion.should_receive(:running?).and_return(false) command = Fission::Command::Delete.new @target_vm command.execute @string_io.string.should match /Deletion complete/ end it "should output an error and exit if unable to determine if it's running" do @running_response_mock.stub_as_unsuccessful command = Fission::Command::Delete.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error determining if the VM is running.+it blew up.+/m end it 'should output an error and exit if there was an error deleting the VM' do @delete_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:delete).and_return(@delete_response_mock) command = Fission::Command::Delete.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error deleting the VM.+it blew up/m end it 'should output an error and exit if the VM is running' do @running_response_mock.stub_as_successful true command = Fission::Command::Delete.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /VM is currently running/ @string_io.string.should match /Either stop\/suspend the VM or use '--force' and try again/ end it 'should output an error and exit if the fusion app is running' do Fission::Fusion.stub(:running?).and_return(true) command = Fission::Command::Delete.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Fusion GUI is currently running/ @string_io.string.should match /Either exit the Fusion GUI or use '--force' and try again/ @string_io.string.should match /NOTE: Forcing a VM deletion with the Fusion GUI running may not clean up all of the VM metadata/ end describe 'with --force' do before do @vm_mock.should_receive(:delete).and_return(@delete_response_mock) @delete_response_mock.stub_as_successful true end it "should stop the VM if it's running and then delete it" do @stop_cmd_mock = double('stop_cmd') @stop_cmd_mock.should_receive(:execute) @running_response_mock.stub_as_successful true Fission::Command::Stop.should_receive(:new).with(@target_vm). and_return(@stop_cmd_mock) command = Fission::Command::Delete.new @target_vm << '--force' command.execute @string_io.string.should match /VM is currently running/ @string_io.string.should match /Going to stop it/ @string_io.string.should match /Deletion complete/ end it 'should output a warning about fusion metadata issue and then delete the VM' do Fission::Fusion.should_receive(:running?).and_return(true) command = Fission::Command::Delete.new @target_vm << '--force' command.execute @string_io.string.should match /Fusion GUI is currently running/ @string_io.string.should match /metadata for the VM may not be removed completely/ @string_io.string.should match /Deletion complete/ end end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Delete.help output.should match /fission delete TARGET_VM \[OPTIONS\]/ output.should match /--force/ end end end fission-0.5.0/spec/fission/command/clone_spec.rb0000644000076400007640000000550612511713252020710 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Clone do include_context 'command_setup' before do @vm_info = ['foo', 'bar'] @source_vm_mock = double('source_vm') @target_vm_mock = double('target_vm') @clone_response_mock = double('clone_reponse') @start_response_mock = double('start_reponse') @source_vm_mock.stub(:name).and_return('foo') @target_vm_mock.stub(:name).and_return('bar') Fission::VM.stub(:new).with('foo').and_return(@source_vm_mock) Fission::VM.stub(:new).with('bar').and_return(@target_vm_mock) Fission::VM.stub(:clone).with(@vm_info.first, @vm_info[1]). and_return(@clone_response_mock) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Clone.new.command_name.should == 'clone' end end describe 'execute' do subject { Fission::Command::Clone } [ [], ['foo'], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'clone' end it 'should clone the vm' do @clone_response_mock.stub_as_successful command = Fission::Command::Clone.new @vm_info command.execute @string_io.string.should match /Clone complete/ end it 'should output an error and exit if there is an error cloning' do @clone_response_mock.stub_as_unsuccessful command = Fission::Command::Clone.new @vm_info lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error cloning the VM.+it blew up/m end describe 'with --start' do before do @clone_response_mock.stub_as_successful true @target_vm_mock.should_receive(:start).and_return(@start_response_mock) end it 'should clone the vm and start it' do @start_response_mock.stub_as_successful command = Fission::Command::Clone.new @vm_info << '--start' command.execute @string_io.string.should match /Clone complete/ @string_io.string.should match /Starting '#{@vm_info[1]}'/ @string_io.string.should match /VM '#{@vm_info[1]}' started/ end it 'should output an error and exit if there is an error starting the VM after cloning it' do @start_response_mock.stub_as_unsuccessful command = Fission::Command::Clone.new @vm_info << '--start' lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Clone complete/ @string_io.string.should match /Starting '#{@vm_info[1]}'/ @string_io.string.should match /There was an error starting the VM.+it blew up/m end end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Clone.help output.should match /fission clone SOURCE_VM TARGET_VM.+OPTIONS/m end end end fission-0.5.0/spec/fission/command/suspend_spec.rb0000644000076400007640000000623112511713252021265 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Suspend do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @suspend_response_mock = double('suspend_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Suspend.new.command_name.should == 'suspend' end end describe 'execute' do subject { Fission::Command::Suspend } [ [], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'suspend' end it 'should suspend the vm' do @suspend_response_mock.stub_as_successful @vm_mock.should_receive(:suspend).and_return(@suspend_response_mock) command = Fission::Command::Suspend.new @target_vm command.execute @string_io.string.should match /Suspending '#{@target_vm.first}'/ @string_io.string.should match /VM '#{@target_vm.first}' suspended/ end it 'should output an error and exit if there was an error suspending the vm' do @suspend_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:suspend).and_return(@suspend_response_mock) command = Fission::Command::Suspend.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Suspending '#{@target_vm.first}'/ @string_io.string.should match /There was an error suspending the VM.+it blew up.+/m end describe 'with --all' do before do @vm_mock_1 = double('vm_mock_1') @vm_mock_2 = double('vm_mock_2') @vm_mock_1.stub(:name).and_return('vm_1') @vm_mock_2.stub(:name).and_return('vm_2') @vm_items = {'vm_1' => @vm_mock_1, 'vm_2' => @vm_mock_2 } end it 'should output an error and exit if there was an error getting the list of running vms' do @all_running_response_mock.stub_as_unsuccessful Fission::VM.should_receive(:all_running).and_return(@all_running_response_mock) command = Fission::Command::Suspend.new ['--all'] lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error getting the list of running VMs.+it blew up.+/m end it 'should suspend all running VMs' do @all_running_response_mock.stub_as_successful @vm_items.values @suspend_response_mock.stub_as_successful Fission::VM.should_receive(:all_running).and_return(@all_running_response_mock) @vm_items.each_pair do |name, mock| mock.should_receive(:suspend).and_return(@suspend_response_mock) end command = Fission::Command::Suspend.new ['--all'] command.execute @vm_items.keys.each do |vm| @string_io.string.should match /Suspending '#{vm}'/ @string_io.string.should match /VM '#{vm}' suspended/ end end end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Suspend.help output.should match /fission suspend \[TARGET_VM \| --all\]/ end end end fission-0.5.0/spec/fission/command/start_spec.rb0000644000076400007640000000343012511713252020737 0ustar pravipravirequire 'spec_helper' describe Fission::Command::Start do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @start_response_mock = double('start_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::Start.new.command_name.should == 'start' end end describe 'execute' do subject { Fission::Command::Start } [ [], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'start' end it 'should output an error and exit if there was an error starting the vm' do @start_response_mock.stub_as_unsuccessful @vm_mock.should_receive(:start).and_return(@start_response_mock) command = Fission::Command::Start.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /Starting '#{@target_vm.first}'/ @string_io.string.should match /There was a problem starting the VM.+it blew up.+/m end describe 'with --headless' do it 'should start the vm headless' do @start_response_mock.stub_as_successful @vm_mock.should_receive(:start).and_return(@start_response_mock) command = Fission::Command::Start.new @target_vm << '--headless' command.execute @string_io.string.should match /Starting '#{@target_vm.first}'/ @string_io.string.should match /VM '#{@target_vm.first}' started/ end end end describe 'help' do it 'should output info for this command' do output = Fission::Command::Start.help output.should match /fission start TARGET_VM \[OPTIONS\]/ output.should match /--headless/ end end end fission-0.5.0/spec/fission/command/snapshot_list_spec.rb0000644000076400007640000000364112511713252022500 0ustar pravipravirequire 'spec_helper' describe Fission::Command::SnapshotList do include_context 'command_setup' before do @target_vm = ['foo'] Fission::VM.stub(:new).and_return(@vm_mock) @snap_list_response_mock = double('snap_list_response') @vm_mock.stub(:name).and_return(@target_vm.first) end describe 'command_name' do it 'should return the pretty command name' do Fission::Command::SnapshotList.new.command_name.should == 'snapshot list' end end describe 'execute' do before do @vm_mock.stub(:snapshots).and_return(@snap_list_response_mock) end subject { Fission::Command::SnapshotList } [ [], ['--bar'] ].each do |args| it_should_not_accept_arguments_of args, 'snapshot list' end it 'should output the list of snapshots if any exist' do @snap_list_response_mock.stub_as_successful ['snap 1', 'snap 2', 'snap 3'] command = Fission::Command::SnapshotList.new @target_vm command.execute @string_io.string.should match /snap 1\nsnap 2\nsnap 3\n/ end it 'should output that it could not find any snapshots if none exist' do @snap_list_response_mock.stub_as_successful [] command = Fission::Command::SnapshotList.new @target_vm command.execute @string_io.string.should match /No snapshots found for VM '#{@target_vm.first}'/ end it 'should output an error and exit if there was an error getting the list of snapshots' do @snap_list_response_mock.stub_as_unsuccessful command = Fission::Command::SnapshotList.new @target_vm lambda { command.execute }.should raise_error SystemExit @string_io.string.should match /There was an error listing the snapshots.+it blew up.+/m end end describe 'help' do it 'should output info for this command' do output = Fission::Command::SnapshotList.help output.should match /fission snapshot list TARGET_VM/ end end end fission-0.5.0/spec/fission/cli_spec.rb0000644000076400007640000000263712511713252016743 0ustar pravipravirequire 'spec_helper' describe Fission::CLI do before do @string_io = StringIO.new Fission::CLI.any_instance.stub(:ui).and_return(Fission::UI.new(@string_io)) @parser = double('parser') @parser.stub :parse @parser.stub :command end describe 'initialize' do it 'should create a parse object using ARGV' do Fission::CommandLineParser.should_receive(:new).with(ARGV). and_return(@parser) Fission::CLI.new end it 'should create a parse object with the provided args' do Fission::CommandLineParser.should_receive(:new).with(['foo']). and_return(@parser) Fission::CLI.new ['foo'] end it 'should create a parse object using our parser' do @parser.should_receive(:new).with(ARGV).and_return(@parser) Fission::CLI.new nil, @parser end it 'should parse the arguments using the parser' do @parser.should_receive(:new).with(ARGV).and_return(@parser) @parser.should_receive :parse Fission::CLI.new nil, @parser end end describe 'execute' do it 'should execute the parsed command' do @cmd_mock = double('cmd') @cmd_mock.should_receive :execute @parser.stub(:new).and_return(@parser) @parser.stub(:command).and_return(@cmd_mock) Fission::CLI.new(nil, @parser).execute end end end fission-0.5.0/spec/fission/ui_spec.rb0000644000076400007640000000154712511713252016610 0ustar pravipravirequire 'spec_helper' describe Fission::UI do before do @string_io = StringIO.new end describe 'output' do it 'should show the desired text' do Fission::UI.new(@string_io).output "foo bar\nbaz blah" @string_io.string.should == "foo bar\nbaz blah\n" end end describe 'output_printf' do it 'should pass the arguments to printf' do @output = double('output') @output.should_receive(:printf).with('foo', 'bar', 'baz') Fission::UI.new(@output).output_printf('foo', 'bar', 'baz') end end describe 'output_and_exit' do it 'should show the desired text and exit with the desired exit code' do Fission::UI.any_instance.should_receive(:exit).and_return(1) Fission::UI.new(@string_io).output_and_exit "foo bar\nbaz blah", 1 @string_io.string.should == "foo bar\nbaz blah\n" end end end fission-0.5.0/spec/fission/metadata_spec.rb0000644000076400007640000001043712511713252017751 0ustar pravipravirequire 'spec_helper' describe Fission::Metadata do before do @plist_mock = double('plist_mock') @plist_file_path = Fission.config['plist_file'] @metadata = Fission::Metadata.new end describe 'load' do it 'should load the existing data' do plist = {'vm_list' => ['1', '2', '3']} CFPropertyList::List.should_receive(:new). with(:file => @plist_file_path). and_return(@plist_mock) @plist_mock.stub(:value).and_return(plist) CFPropertyList.should_receive(:native_types).with(plist). and_return([1, 2, 3]) @metadata.load @metadata.content.should == [1, 2, 3] end end describe 'delete_vm_restart_document' do before do vm_dir = Fission.config['vm_dir'] @foo_vm_dir = File.join vm_dir, 'foo.vmwarevm' @bar_vm_dir = File.join vm_dir, 'bar.vmwarevm' @data = { 'PLRestartDocumentPaths' => [@foo_vm_dir, @bar_vm_dir]} @metadata.content = @data end it 'should remove the vm item from the list if the vm path is in the list' do @metadata.delete_vm_restart_document(Fission::VM.new('foo').path) @metadata.content.should == { 'PLRestartDocumentPaths' => [@bar_vm_dir]} end it 'should not doing anything if the vm is not in the list' do @metadata.delete_vm_restart_document(Fission::VM.new('baz').path) @metadata.content.should == @data end it 'should not do anything if the restart document list does not exist' do other_data = { 'OtherConfigItem' => ['foo', 'bar']} @metadata.content = other_data @metadata.delete_vm_restart_document(Fission::VM.new('foo').path) @metadata.content.should == other_data end end describe 'delete_vm_favorite_entry' do before do foo_vm_dir = File.join Fission.config['vm_dir'], 'foo.vmwarevm' @data = { 'VMFavoritesListDefaults2' => [{'path' => foo_vm_dir}] } @metadata.content = @data end it 'should remove the vm item from the list' do @metadata.delete_vm_favorite_entry(Fission::VM.new('foo').path) @metadata.content.should == { 'VMFavoritesListDefaults2' => [] } end it 'should not do anything if the vm is not in the list' do @metadata.delete_vm_favorite_entry(Fission::VM.new('bar').path) @metadata.content.should == @data end it 'should ignore VMFavoritesListDefaults2 in Fussion 5' do data = {} @metadata.content = data @metadata.delete_vm_favorite_entry(Fission::VM.new('bar').path) @metadata.content.should == data end it 'should remove the vm item from the list in Fussion 5' do foo_vm_dir = File.join Fission.config['vm_dir'], 'foo.vmwarevm' data = {"fusionInitialSessions" => [{"documentPath" => foo_vm_dir}]} @metadata.content = data @metadata.delete_vm_favorite_entry(Fission::VM.new('foo').path) @metadata.content.should == { 'fusionInitialSessions' => []} end end describe 'self.delete_vm_info' do before do @md_mock = double('metadata_mock') @md_mock.should_receive(:load) @md_mock.should_receive(:save) Fission::Metadata.stub(:new).and_return(@md_mock) @foo_vm_dir = File.join Fission.config['vm_dir'], 'foo.vmwarevm' end it 'should remove the vm from the restart document list' do @md_mock.should_receive(:delete_vm_restart_document).with(@foo_vm_dir) @md_mock.stub(:delete_vm_favorite_entry) Fission::Metadata.delete_vm_info(Fission::VM.new('foo').path) end it 'should remove the vm from the favorite list' do @md_mock.should_receive(:delete_vm_favorite_entry).with(@foo_vm_dir) @md_mock.stub(:delete_vm_restart_document) Fission::Metadata.delete_vm_info(Fission::VM.new('foo').path) end end describe 'save' do it 'should save the data' do CFPropertyList::List.should_receive(:new).and_return(@plist_mock) CFPropertyList.should_receive(:guess).with([1, 2, 3]). and_return(['1', '2', '3']) @plist_mock.should_receive(:value=).with(['1', '2', '3']) @plist_mock.should_receive(:save). with(@plist_file_path, CFPropertyList::List::FORMAT_BINARY) @metadata.content = [1, 2, 3] @metadata.save end end end fission-0.5.0/spec/fission/lease_spec.rb0000644000076400007640000001644112511713252017263 0ustar pravipravirequire 'spec_helper' describe Fission::Lease do before do @lease_info = [ { :ip_address => '172.16.248.197', :mac_address => '00:0c:29:2b:af:50', :start => '2011/10/11 01:50:58', :end => '2011/10/11 02:20:58' }, { :ip_address => '172.16.248.170', :mac_address => '00:0c:29:b3:63:d0', :start => '2010/03/01 00:54:52', :end => '2010/03/01 01:24:52' }, { :ip_address => '172.16.248.132', :mac_address => '00:0c:29:10:23:57', :start => '2010/07/12 21:31:28', :end => '2010/07/12 22:01:28' }, { :ip_address => '172.16.248.150', :mac_address => '00:0c:29:b3:63:d0', :start => '2010/05/27 00:54:52', :end => '2010/05/27 01:24:52' }, { :ip_address => '172.16.248.130', :mac_address => '00:0c:29:b3:63:d0', :start => '2010/04/15 00:54:52', :end => '2010/04/15 01:24:52' }, { :ip_address => '172.16.248.129', :mac_address => '00:0c:29:0a:e9:b3', :start => '2010/02/16 23:16:05', :end => '2010/02/16 23:46:05' } ] @lease_file_content = '# This is a comment # And here is another lease 172.16.248.197 { starts 2 2011/10/11 01:50:58; ends 2 2011/10/11 02:20:58; hardware ethernet 00:0c:29:2b:af:50; } lease 172.16.248.170 { starts 4 2010/03/01 00:54:52; ends 4 2010/03/01 01:24:52; hardware ethernet 00:0c:29:b3:63:d0; } lease 172.16.248.132 { starts 1 2010/07/12 21:31:28; ends 1 2010/07/12 22:01:28; hardware ethernet 00:0c:29:10:23:57; } lease 172.16.248.150 { starts 4 2010/05/27 00:54:52; ends 4 2010/05/27 01:24:52; hardware ethernet 00:0c:29:b3:63:d0; } lease 172.16.248.130 { starts 4 2010/04/15 00:54:52; ends 4 2010/04/15 01:24:52; hardware ethernet 00:0c:29:b3:63:d0; } lease 172.16.248.129 { starts 2 2010/02/16 23:16:05; ends 2 2010/02/16 23:46:05; hardware ethernet 00:0c:29:0a:e9:b3; }' end describe 'new' do it 'should set the ip address' do lease = Fission::Lease.new :ip_address => '127.0.0.1' lease.ip_address.should == '127.0.0.1' end it 'should set the mac address' do lease = Fission::Lease.new :mac_address => '00:00:00:00:00:00' lease.mac_address.should == '00:00:00:00:00:00' end it 'should set the lease start date/time' do date_time = DateTime.parse('2000/01/01 17:00:00') lease = Fission::Lease.new :start => date_time lease.start.should == date_time end it 'should set the lease end date/time' do date_time = DateTime.parse('2000/01/01 17:00:00') lease = Fission::Lease.new :end => date_time lease.end.should == date_time end end describe 'expired?' do it 'should return true if the lease is expired' do lease = Fission::Lease.new :end => DateTime.now - 1 lease.expired?.should == true end it 'should return false if the lease has not expired' do lease = Fission::Lease.new :end => DateTime.now + 1 lease.expired?.should == false end end describe 'self.all' do context 'when the lease file exists' do before do File.should_receive(:file?). with(Fission.config['lease_file']). and_return(true) end it 'returns a response with the list of the found leases' do File.should_receive(:read). with(Fission.config['lease_file']). and_return(@lease_file_content) example_leases = @lease_info.collect do |lease| Fission::Lease.new :ip_address => lease[:ip_address], :mac_address => lease[:mac_address], :start => DateTime.parse(lease[:start]), :end => DateTime.parse(lease[:end]) end response = Fission::Lease.all response.should be_a_successful_response response.data.each do |lease| example_lease = example_leases.select { |l| l.ip_address == lease.ip_address } [:ip_address, :mac_address, :start, :end].each do |attrib| lease.send(attrib).should == example_lease.first.send(attrib) end end end it 'a response with an empty list if there are no leases found' do File.should_receive(:read). with(Fission.config['lease_file']). and_return('') response = Fission::Lease.all response.should be_a_successful_response response.data.should == [] end end context 'when the lease file does not exist' do before do File.should_receive(:file?). with(Fission.config['lease_file']). and_return(false) end it 'should return an unsuccessful response if the configured lease file does not exist' do response = Fission::Lease.all error_string = "Unable to find the lease file '#{Fission.config['lease_file']}'" response.should be_an_unsuccessful_response(error_string) end end end describe 'self.find_by_mac_address' do describe 'when able to get all of the leases' do before do File.stub(:file?).and_return(true) File.stub(:read).and_return(@lease_file_content) end context 'when there are multiple leases for the mac address' do it 'should return the lease with the latest expiration' do response = Fission::Lease.find_by_mac_address '00:0c:29:b3:63:d0' response.should be_a_successful_response response.data.ip_address.should == '172.16.248.150' response.data.mac_address.should == '00:0c:29:b3:63:d0' response.data.start.should == DateTime.parse('2010/05/27 00:54:52') response.data.end.should == DateTime.parse('2010/05/27 01:24:52') end end it 'should return a response with the lease associated with the provided mac address' do response = Fission::Lease.find_by_mac_address '00:0c:29:10:23:57' response.should be_a_successful_response response.data.ip_address.should == '172.16.248.132' response.data.mac_address.should == '00:0c:29:10:23:57' response.data.start.should == DateTime.parse('2010/07/12 21:31:28') response.data.end.should == DateTime.parse('2010/07/12 22:01:28') end it "should return a response with nil if the mac address can't be found" do response = Fission::Lease.find_by_mac_address('00:11:22:33:44:55') response.should be_a_successful_response response.data.should be_nil end end it 'should return an unsuccessful response if there was an error getting all of the leases' do @all_response_mock = double('all_response') @all_response_mock.stub_as_unsuccessful Fission::Lease.stub(:all).and_return(@all_response_mock) response = Fission::Lease.find_by_mac_address('00:11:22:33:44:55') response.should be_an_unsuccessful_response end end end fission-0.5.0/LICENSE0000644000076400007640000000211312511713252013223 0ustar pravipraviThe MIT License Copyright (c) 2011 Thomas Bishop, bishop.thomas@gmail.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. fission-0.5.0/.rspec0000644000076400007640000000001112511713252013326 0ustar pravipravi--colour fission-0.5.0/fission.gemspec0000644000076400007640000000172512511713252015245 0ustar pravipravi# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "fission/version" Gem::Specification.new do |s| s.name = "fission" s.version = Fission::VERSION s.platform = Gem::Platform::RUBY s.authors = ['Tommy Bishop'] s.email = ['bishop.thomas@gmail.com'] s.homepage = "https://github.com/thbishop/fission" s.summary = %q{Command line tool to manage VMware Fusion VMs} s.description = %q{A simple utility to manage VMware Fusion VMs from the command line} s.rubyforge_project = "fission" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.add_dependency 'CFPropertyList', '~> 2.2' s.add_development_dependency 'rake' s.add_development_dependency 'fakefs', '~> 0.4.3' s.add_development_dependency 'rspec', '~> 2.14' end fission-0.5.0/.travis.yml0000644000076400007640000000011612511713252014330 0ustar pravipravilanguage: ruby rvm: - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 script: rake spec fission-0.5.0/bin/0000755000076400007640000000000012511713252012771 5ustar pravipravifission-0.5.0/bin/fission0000755000076400007640000000017412511713252014373 0ustar pravipravi#!/usr/bin/env ruby $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) require 'fission' Fission::CLI.new.execute fission-0.5.0/README.md0000644000076400007640000001022312511713252013476 0ustar pravipravi# Fission [![Build Status](https://secure.travis-ci.org/thbishop/fission.png)](http://travis-ci.org/thbishop/fission) [![Dependency Status](https://gemnasium.com/thbishop/fission.png)](https://gemnasium.com/thbishop/fission) ## Intro Fission is a simple command line tool for managing VMware Fusion VMs. Only Fusion 3.x is currently supported. See [Fusion Version Support](#fusion-version-support) for more info. ## Install gem install fission ## Usage ### Clone fission clone existing_vm new_vm [--start] If you provide '--start', then the new VM will be powered on after cloning ### Delete fission delete my_vm [--force] Deletes the VM. This will delete the files from disk and remove the related metadata in Fusion. By default, the VM will not be deleted if: * The VM is running * The Fusion GUI is running (as the metadata cannot be cleanly removed) Providing '--force' will: * Stop the VM if it's running * Delete the VM even if the Fusion GUI is running ### Info fission info my_vm Outputs information about the VM ### Snapshot Create fission snapshot create my_vm snapshot_name Creates a snapshot for the VM In order to create the snapshot: * The VM must be running * The snapshot name must be unique ### Snapshot Delete fission snapshot delete my_vm snapshot_name Deletes a snapshot for the VM If you have the Fusion GUI running, the VM must be running in order to delete the snapshot. ### Snapshot List fission snapshot list my_vm Lists the snapshots for the VM ### Snapshot Revert fission snapshot revert my_vm existing_snapshot Reverts a VM to an existing snapshot In order to revert to the snapshot: * The Fusion GUI cannot be running ### Start fission start my_vm [--headless] Starts the VM Providng '--headless' will start the VM without a Fusion GUI console Note that the Fusion GUI cannot be running to start a VM with '--headless' ### Status fission status Displays the status (running or not) of all of the VMs found ### Stop fission stop my_vm Stops the VM ### Suspend fission suspend [my_vm | --all] Suspends the VM or all running VMs ### Help fission -h or just fission ## Configuration By default, fission will use the default VMware Fusion VM directory (~/Documents/Virtual Machines.localized/) when cloning. If you want to use a different directory, you can set this in a config file. The config file needs to be in YAML format and live at '~/.fissionrc' $cat ~/.fissionrc --- vm_dir: "/vm" ## Fusion Version Support As of now, only Fusion 3.x is supported (that's what I have available to test). It's my understanding that some folks are currently using fission with Fusion 4.x as well. In order to have fission work with Fusion 4.x, you will need to tell fission where the Fusion 4.x vmrun file is. You can do so with the following item placed in your ~/.fissionrc (remember, YAML format): vmrun_bin: /Applications/VMware Fusion.app/Contents/Library/vmrun ## Other Notable Info The name of the VM used in the previous examples should be the directory name of the VM minus the '.vmwarevm' extension. Typically the VM name and the directory name are the same. As of now, VMware Fusion doesn't provide an easy, out of the box, way to modify the personality (hostname, ip, etc.) of a VM. Because of this, a clone created by fission is an _exact_ copy of the original (including hostname, ip address, etc.). Most likely, this isn't what you want. One approach is to create a VM which will act as a template. Create the VM with the desired install method (ideally with easy install) and settings, but do not power on the VM. You can then create clones from this VM 'template'. When you power on the clone, it will start the OS install process (and assign a new ip, etc.). ## Fission with RVM Please see the following gist for a walkthrough of making fission available regardless of ruby environment when using RVM https://gist.github.com/1203167 ## Contribute * Fork the project * Make your feature addition or bug fix (with tests and docs) in a topic branch * Bonus points for not mucking with the gemspec or version * Send a pull request and I'll get it integrated ## License See LICENSE fission-0.5.0/CHANGELOG.md0000644000076400007640000000214412511713252014033 0ustar pravipravi## head ## 0.5.0 (10/04/2013) * update CFPropertyList to 2.2 ## 0.5.0.beta.1 (06/22/2013) * add 'info' command * add 'snapshot delete' command * add ability to get all VM config values (related to #14) * fix issue #16 (returning incorrect mac address) * fix issue #18 (1.8.7 compatibility) * fix issue #19 (duplicate config entires when cloning) * internal cleanup of how command strings are handled (props to @patdowney) * bump dependency on CFproperList to avoid libxml-ruby dependency (#24) ## 0.4.0 (01/17/2012) * major internal refactoring for usage as a lib * add fix for loading a custom vmrun_bin in ~/.fissionrc (issue #8) * add guestos and uuid methods to VM (@ody) ## 0.3.0 (09/16/2011) * add ability to suspend all running VMs ('--all') * add 'delete' command * add 'snapshot create' command * add 'snapshot list' command * add 'snapshot revert' command * add '--headless' option to start * fix issue #2 ## 0.2.0 (07/13/2011) * add 'status' command * add 'start' command * add 'stop' command * add 'suspend' command * add support for cloning single and split disk VMs ## 0.1.0 (05/17/2011) Initial release fission-0.5.0/Gemfile0000644000076400007640000000013312511713252013511 0ustar pravipravisource "http://rubygems.org" # Specify your gem's dependencies in fission.gemspec gemspec fission-0.5.0/.ruby-version0000644000076400007640000000001312511713252014660 0ustar pravipravi1.9.3-p448 fission-0.5.0/.ruby-gemset0000644000076400007640000000001012511713252014454 0ustar pravipravifission fission-0.5.0/metadata.yml0000644000076400007640000001566212511713252014536 0ustar pravipravi--- !ruby/object:Gem::Specification name: fission version: !ruby/object:Gem::Version version: 0.5.0 prerelease: platform: ruby authors: - Tommy Bishop autorequire: bindir: bin cert_chain: [] date: 2013-10-05 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: CFPropertyList requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.2' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.2' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: fakefs requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 0.4.3 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 0.4.3 - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.14' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.14' description: A simple utility to manage VMware Fusion VMs from the command line email: - bishop.thomas@gmail.com executables: - fission extensions: [] extra_rdoc_files: [] files: - .gitignore - .rspec - .ruby-gemset - .ruby-version - .travis.yml - CHANGELOG.md - Gemfile - LICENSE - README.md - Rakefile - bin/fission - fission.gemspec - lib/fission.rb - lib/fission/action/shell_executor.rb - lib/fission/action/snapshot/creator.rb - lib/fission/action/snapshot/deleter.rb - lib/fission/action/snapshot/lister.rb - lib/fission/action/snapshot/reverter.rb - lib/fission/action/vm/cloner.rb - lib/fission/action/vm/deleter.rb - lib/fission/action/vm/lister.rb - lib/fission/action/vm/starter.rb - lib/fission/action/vm/stopper.rb - lib/fission/action/vm/suspender.rb - lib/fission/cli.rb - lib/fission/command.rb - lib/fission/command/clone.rb - lib/fission/command/delete.rb - lib/fission/command/info.rb - lib/fission/command/snapshot_create.rb - lib/fission/command/snapshot_delete.rb - lib/fission/command/snapshot_list.rb - lib/fission/command/snapshot_revert.rb - lib/fission/command/start.rb - lib/fission/command/status.rb - lib/fission/command/stop.rb - lib/fission/command/suspend.rb - lib/fission/command_helpers.rb - lib/fission/command_line_parser.rb - lib/fission/config.rb - lib/fission/core_ext/class.rb - lib/fission/core_ext/file.rb - lib/fission/core_ext/object.rb - lib/fission/fusion.rb - lib/fission/lease.rb - lib/fission/metadata.rb - lib/fission/response.rb - lib/fission/ui.rb - lib/fission/version.rb - lib/fission/vm.rb - lib/fission/vm_configuration.rb - spec/contexts/command.rb - spec/fission/action/execute_shell_command_spec.rb - spec/fission/action/snapshot/creator_spec.rb - spec/fission/action/snapshot/deleter_spec.rb - spec/fission/action/snapshot/lister_spec.rb - spec/fission/action/snapshot/reverter_spec.rb - spec/fission/action/vm/cloner_spec.rb - spec/fission/action/vm/deleter_spec.rb - spec/fission/action/vm/lister_spec.rb - spec/fission/action/vm/starter_spec.rb - spec/fission/action/vm/stopper_spec.rb - spec/fission/action/vm/suspender_spec.rb - spec/fission/cli_spec.rb - spec/fission/command/clone_spec.rb - spec/fission/command/delete_spec.rb - spec/fission/command/info_spec.rb - spec/fission/command/snapshot_create_spec.rb - spec/fission/command/snapshot_delete_spec.rb - spec/fission/command/snapshot_list_spec.rb - spec/fission/command/snapshot_revert_spec.rb - spec/fission/command/start_spec.rb - spec/fission/command/status_spec.rb - spec/fission/command/stop_spec.rb - spec/fission/command/suspend_spec.rb - spec/fission/command_helpers_spec.rb - spec/fission/command_line_parser_spec.rb - spec/fission/command_spec.rb - spec/fission/config_spec.rb - spec/fission/fusion_spec.rb - spec/fission/lease_spec.rb - spec/fission/metadata_spec.rb - spec/fission/response_spec.rb - spec/fission/ui_spec.rb - spec/fission/vm_configuration_spec.rb - spec/fission/vm_spec.rb - spec/fission_spec.rb - spec/helpers/command_helpers.rb - spec/helpers/response_helpers.rb - spec/matchers/be_a_successful_response.rb - spec/matchers/be_an_unsuccessful_response.rb - spec/spec_helper.rb homepage: https://github.com/thbishop/fission licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: fission rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: Command line tool to manage VMware Fusion VMs test_files: - spec/contexts/command.rb - spec/fission/action/execute_shell_command_spec.rb - spec/fission/action/snapshot/creator_spec.rb - spec/fission/action/snapshot/deleter_spec.rb - spec/fission/action/snapshot/lister_spec.rb - spec/fission/action/snapshot/reverter_spec.rb - spec/fission/action/vm/cloner_spec.rb - spec/fission/action/vm/deleter_spec.rb - spec/fission/action/vm/lister_spec.rb - spec/fission/action/vm/starter_spec.rb - spec/fission/action/vm/stopper_spec.rb - spec/fission/action/vm/suspender_spec.rb - spec/fission/cli_spec.rb - spec/fission/command/clone_spec.rb - spec/fission/command/delete_spec.rb - spec/fission/command/info_spec.rb - spec/fission/command/snapshot_create_spec.rb - spec/fission/command/snapshot_delete_spec.rb - spec/fission/command/snapshot_list_spec.rb - spec/fission/command/snapshot_revert_spec.rb - spec/fission/command/start_spec.rb - spec/fission/command/status_spec.rb - spec/fission/command/stop_spec.rb - spec/fission/command/suspend_spec.rb - spec/fission/command_helpers_spec.rb - spec/fission/command_line_parser_spec.rb - spec/fission/command_spec.rb - spec/fission/config_spec.rb - spec/fission/fusion_spec.rb - spec/fission/lease_spec.rb - spec/fission/metadata_spec.rb - spec/fission/response_spec.rb - spec/fission/ui_spec.rb - spec/fission/vm_configuration_spec.rb - spec/fission/vm_spec.rb - spec/fission_spec.rb - spec/helpers/command_helpers.rb - spec/helpers/response_helpers.rb - spec/matchers/be_a_successful_response.rb - spec/matchers/be_an_unsuccessful_response.rb - spec/spec_helper.rb fission-0.5.0/lib/0000755000076400007640000000000012511713252012767 5ustar pravipravifission-0.5.0/lib/fission.rb0000644000076400007640000000270712511713252014774 0ustar pravipravirequire 'fileutils' require 'optparse' require 'ostruct' require 'yaml' $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib]) require 'fission/action/shell_executor' require 'fission/action/snapshot/creator' require 'fission/action/snapshot/deleter' require 'fission/action/snapshot/lister' require 'fission/action/snapshot/reverter' require 'fission/action/vm/cloner' require 'fission/action/vm/deleter' require 'fission/action/vm/lister' require 'fission/action/vm/starter' require 'fission/action/vm/stopper' require 'fission/action/vm/suspender' require 'fission/cli' require 'fission/command' require 'fission/command_helpers' require 'fission/command_line_parser' require 'fission/command/clone' require 'fission/command/delete' require 'fission/command/info' require 'fission/command/snapshot_create' require 'fission/command/snapshot_delete' require 'fission/command/snapshot_list' require 'fission/command/snapshot_revert' require 'fission/command/start' require 'fission/command/status' require 'fission/command/stop' require 'fission/command/suspend' require 'fission/config' require 'fission/core_ext/class' require 'fission/core_ext/file' require 'fission/core_ext/object' require 'fission/fusion' require 'fission/lease' require 'fission/metadata' require 'fission/response' require 'fission/ui' require 'fission/vm' require 'fission/vm_configuration' require 'fission/version' module Fission extend self def config @config ||= Config.new end end fission-0.5.0/lib/fission/0000755000076400007640000000000012511713252014441 5ustar pravipravifission-0.5.0/lib/fission/cli.rb0000644000076400007640000000157312511713252015543 0ustar pravipravimodule Fission class CLI # Internal: Creates a new Fission::CLI object. This automatically parses # the arguments in ARGV. This will also automatically display the usage # and exit if applicable. # # Examples # # Fission::CLI.new # # Returns a Fission::CLI object. def initialize(args=ARGV, parser=CommandLineParser) @args = args ||= ARGV @parser = parser.new @args parse_arguments end # Internal: Execute the determined command. # # Examples: # # Fission::CLI.new(ARGV).execute # # Returns nothing. def execute @cmd.execute end private # Internal: Parses the arguments using the parser. # # Examples: # # @cli.parse_arguments # # Returns nothing. def parse_arguments @parser.parse @cmd = @parser.command end end end fission-0.5.0/lib/fission/action/0000755000076400007640000000000012511713252015716 5ustar pravipravifission-0.5.0/lib/fission/action/shell_executor.rb0000644000076400007640000000155312511713252021274 0ustar pravipravimodule Fission module Action class ShellExecutor # Internal: Create a new ShellExecutor object. # # cmd - Command to execute as a String # # Examples: # # Fission::Action::ShellExecutor.new 'ls /var/log' # # Returns a new Fission::Action::ShellExecutor object. def initialize(cmd) @cmd = cmd end # Internal: Executes the command in the shell. The command will be # executed using the ruby '`' method. # # Examples: # # @executor.execute # # Returns a Hash with two keys. # The key 'output' will contain the output from the command. # The key 'process_status' will conatian a standard ruby Process::Status # object. def execute { 'output' => `#{@cmd}`, 'process_status' => $? } end end end end fission-0.5.0/lib/fission/action/vm/0000755000076400007640000000000012511713252016340 5ustar pravipravifission-0.5.0/lib/fission/action/vm/stopper.rb0000644000076400007640000000453212511713252020365 0ustar pravipravimodule Fission module Action module VM class Stopper # Internal: Creates a new VMStopper object. This accepts a VM object. # # vm - An instance of VM # # Examples: # # Fission::Action::VMStopper.new @my_vm # # Returns a new VMStopper object def initialize(vm) @vm = vm end # Public: Stops a VM. The VM must be running in order to stop it. # # options - Hash of options: # :hard - Boolean which specifies to power off the VM (instead # of attempting to initiate a graceful shutdown). This # is the equivalent of passing 'hard' to the vmrun # stop command. # (default: false) # # Examples # # @stopper.stop # # @stopper.stop :hard => true # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def stop(options={}) unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end running_response = @vm.running? return running_response unless running_response.successful? unless running_response.data return Response.new :code => 1, :message => 'VM is not running' end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? command = "#{vmrun_cmd} stop " command << "'#{conf_file_response.data}' " command << 'hard ' unless options[:hard].blank? command << '2>&1' command_exec = Fission::Action::ShellExecutor.new command Response.from_shell_executor command_exec.execute end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @vm_stopper.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/vm/suspender.rb0000644000076400007640000000355512511713252020705 0ustar pravipravimodule Fission module Action module VM class Suspender # Internal: Creates a new VMSuspender object. This accepts a VM object. # # vm - An instance of VM # # Examples: # # Fission::Action::VMSuspender.new @my_vm # # Returns a new VMSuspender object def initialize(vm) @vm = vm end # Public: Suspends a VM. The VM must be running in order to suspend it. # # Examples # # @suspender.suspend # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def suspend unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end running_response = @vm.running? return running_response unless running_response.successful? unless running_response.data return Response.new :code => 1, :message => 'VM is not running' end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? command = "#{vmrun_cmd} suspend " command << "'#{conf_file_response.data}' 2>&1" command_exec = Fission::Action::ShellExecutor.new command Response.from_shell_executor command_exec.execute end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @suspender.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/vm/deleter.rb0000644000076400007640000000442112511713252020312 0ustar pravipravimodule Fission module Action module VM class Deleter # Internal: Creates a new VMDeleter object. This accepts a VM object. # # vm - An instance of VM # # Examples: # # Fission::Action::VMDeleter.new @my_vm # # Returns a new VMDeleter object def initialize(vm) @vm = vm end # Public: Deletes a VM. The VM must not be running in order to delete # it. As there are a number issues with the Fusion command line tool for # deleting VMs, this is a best effort. The VM must not be running when # this method is called. This essentially deletes the VM directory and # attempts to remove the relevant entries from the Fusion plist file. # It's highly recommended to delete VMs without the Fusion GUI running. # If the Fusion GUI is running this method should succeed, but it's # been observed that Fusion will recreate the plist data which is # deleted. This leads to 'missing' VMs in the Fusion GUI. # # Examples # # @deleter.delete # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def delete unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end running_response = @vm.running? return running_response unless running_response.successful? if running_response.data message = 'The VM must not be running in order to delete it.' return Response.new :code => 1, :message => message end FileUtils.rm_rf @vm.path Metadata.delete_vm_info @vm.path Response.new :code => 0 end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @deleter.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/vm/lister.rb0000644000076400007640000001061412511713252020171 0ustar pravipravimodule Fission module Action module VM class Lister # Public: Provides all of the VMs which are located in the VM directory. # # Examples # # Fission::VM.all.data # # => [, # ] # # Returns a Response with the result. # If successful, the Response's data attribute will be an Array of VM # objects. If no VMs are found, the Response's data attribute will be an # empty Array. # If there is an error, an unsuccessful Response will be returned. def all vm_dirs = Dir[File.join Fission.config['vm_dir'], '*.vmwarevm'].select do |d| File.directory? d end response = Response.new :code => 0 response.data = vm_dirs.collect do |dir| Fission::VM.new(File.basename dir, '.vmwarevm') end response end # Public: Provides all of the VMs which are currently running. # # Examples # # Fission::VM.all_running.data # # => [, # ] # # Returns a Response with the result. # If successful, the Response's data attribute will be an Array of VM # objects which are running. If no VMs are running, the Response's data # attribute will be an empty Array. # If there is an error, an unsuccessful Response will be returned. def all_running command = "#{Fission.config['vmrun_cmd']} list" command_executor = Fission::Action::ShellExecutor.new command result = command_executor.execute response = Response.new :code => result['process_status'].exitstatus if response.successful? response.data = get_vm_objects_from_list_output result['output'] else response.message = result['output'] end response end # Public: Provides a list of all of the VMs and their associated status # # Examples # # Fission::VM.all_with_status.data # # => { 'vm1' => 'running', 'vm2' => 'suspended', 'vm3' => 'not running'} # # Returns a Response with the result. # If successful, the Response's data attribute will be a Hash of with the VM # names as keys and their status as the values. # If there is an error, an unsuccessful Repsonse will be returned. def all_with_status all_response = all return all_response unless all_response.successful? all_vms = all_response.data running_response = all_running return running_response unless running_response.successful? response = Response.new :code => 0 @all_running_vm_names = running_response.data.collect { |v| v.name } response.data = all_vms.inject({}) do |result, vm| result[vm.name] = determine_status vm result end response end private # Internal: Helper to determines the status of a VM. # # vm - The VM object. # # Examples: # # @lister.determine_status my_vm # # => 'suspended' # # Returns a String of the status. def determine_status(vm) return 'running' if @all_running_vm_names.include? vm.name return 'suspended' if vm.suspend_file_exists? return 'not running' end # Internal: Helper to get VM objects from the output of running VMs. # # output - output from the list command. # # Examples: # # @lister.get_vm_objects_from_list_output my_output # # => [, # ] # # Returns an Array of VM objects. def get_vm_objects_from_list_output(output) vms = output.split("\n").select do |vm| vm.include?('.vmx') && File.exists?(vm) && File.extname(vm) == '.vmx' end vms.collect do |vm| Fission::VM.new File.basename(File.dirname(vm), '.vmwarevm') end end end end end end fission-0.5.0/lib/fission/action/vm/cloner.rb0000644000076400007640000001432012511713252020147 0ustar pravipravimodule Fission module Action module VM class Cloner # Internal: Creates a new VMCloner object. This accepts a source and # target VM object. # # source_vm - An instance of VM # target_vm - An instance of VM # # Examples: # # Fission::Action::VMCloner.new @my_source_vm, @my_target_vm # # Returns a new VMCloner object. def initialize(source_vm, target_vm) @source_vm = source_vm @target_vm = target_vm end # Public: Creates a new VM which is a clone of an existing VM. As # Fusion doesn't provide a native cloning mechanism, this is a best # effort. This essentially is a directory copy with updates to relevant # files. It's recommended to clone VMs which are not running. # # Examples # # @cloner.clone # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def clone unless @source_vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end if @target_vm.exists? return Response.new :code => 1, :message => 'VM already exists' end FileUtils.cp_r @source_vm.path, @target_vm.path rename_vm_files @source_vm.name, @target_vm.name update_config @source_vm.name, @target_vm.name Response.new :code => 0 end private # Internal: Renames the files of a newly cloned VM. # # from - The VM name that was used as the source of the clone. # to - The name of the newly cloned VM. # # Examples # # @cloner.rename_vm_files 'foo', 'bar' # # Returns nothing. def rename_vm_files(from, to) files_to_rename(from, to).each do |file| text_to_replace = File.basename(file, File.extname(file)) if File.extname(file) == '.vmdk' if file.match /\-s\d+\.vmdk/ text_to_replace = file.partition(/\-s\d+.vmdk/).first end end unless File.exists?(File.join(@target_vm.path, file.gsub(text_to_replace, to))) FileUtils.mv File.join(@target_vm.path, file), File.join(@target_vm.path, file.gsub(text_to_replace, to)) end end end # Internal: Provides the list of files which need to be renamed in a # newly cloned VM directory. # # from - The VM name that was used as the source of the clone. # to - The name of the newly cloned VM. # # Examples # # @cloner.files_to_rename 'foo', 'bar' # # => ['/vms/vm1/foo.vmdk', '/vms/vm1/foo.vmx', 'vms/vm1/blah.other'] # # Returns an Array containing the paths (String) to the files to rename. # The paths which match the from name will preceed any other files # found in the newly cloned VM directory. def files_to_rename(from, to) files_which_match_source_vm = [] other_files = [] Dir.entries(@target_vm.path).each do |f| unless f == '.' || f == '..' f.include?(from) ? files_which_match_source_vm << f : other_files << f end end files_which_match_source_vm + other_files end # Internal: Provides the list of file extensions for VM related files. # # Examples # # @cloner.vm_file_extension # # => ['.nvram', '.vmdk', '.vmem'] # # Returns an Array containing the file extensions of VM realted files. # The file extensions returned are Strings and include a '.'. def vm_file_extensions ['.nvram', '.vmdk', '.vmem', '.vmsd', '.vmss', '.vmx', '.vmxf'] end # Internal: Updates config files for a newly cloned VM. This will # update any files with the extension of '.vmx', '.vmxf', and '.vmdk'. # Any binary '.vmdk' files will be skipped. # # from - The VM name that was used as the source of the clone. # to - The name of the newly cloned VM. # # Examples # # @cloner.update_config 'foo', 'bar' # # Returns nothing. def update_config(from, to) ['.vmx', '.vmxf', '.vmdk'].each do |ext| file = File.join @target_vm.path, "#{to}#{ext}" unless File.binary?(file) text = (File.read file).gsub from, to File.open(file, 'w'){ |f| f.print text } end clean_up_conf_file(file) if ext == '.vmx' end end # Internal: Cleans up the conf file (*.vmx) for a newly cloned VM. This # includes removing generated MAC addresses, setting up for a new UUID, # and disable VMware tools warning. # # conf_file_path - Aboslute path to the VM's conf file (.vmx). # # Examples # # @cloner.clean_up_conf_file '/vms/foo/foo.vmx' # # Returns nothing. def clean_up_conf_file(conf_file_path) conf_items_patterns = { /^tools\.remindInstall.*\n/ => "tools.remindInstall = \"FALSE\"", /^uuid\.action.*\n/ => "uuid.action = \"create\"", /^ethernet\.+generatedAddress.*\n/ => '' } content = File.read conf_file_path content << "\n" conf_items_patterns.each_pair do |pattern, new_item| unless content.include? new_item content.gsub(pattern, '').strip content << "#{new_item}\n" end end File.open(conf_file_path, 'w') { |f| f.print content } end # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @cloner.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/vm/starter.rb0000644000076400007640000000535012511713252020354 0ustar pravipravimodule Fission module Action module VM class Starter # Internal: Creates a new VMStarter object. This accepts a VM object. # # vm - An instance of VM # # Examples: # # Fission::Action::VMStarter.new @my_vm # # Returns a new VMStarter object def initialize(vm) @vm = vm end # Public: Starts a VM. The VM must not be running in order to start it. # # options - Hash of options: # :headless - Boolean which specifies to start the VM without # a GUI console. The Fusion GUI must not be # running in order to start the VM headless. # (default: false) # # Examples # # @vm_starter.start # # @vm_starter.start :headless => true # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def start(options={}) unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end running_response = @vm.running? return running_response unless running_response.successful? if running_response.data return Response.new :code => 1, :message => 'VM is already running' end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? unless options[:headless].blank? if Fusion.running? message = 'It looks like the Fusion GUI is currently running. ' message << 'A VM cannot be started in headless mode when the Fusion GUI is running. ' message << 'Exit the Fusion GUI and try again.' return Response.new :code => 1, :message => message end end command = "#{vmrun_cmd} start " command << "'#{conf_file_response.data}' " command << (options[:headless].blank? ? 'gui ' : 'nogui ') command << '2>&1' command_exec = Fission::Action::ShellExecutor.new command Response.from_shell_executor command_exec.execute end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @vm_starter.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/snapshot/0000755000076400007640000000000012511713252017555 5ustar pravipravifission-0.5.0/lib/fission/action/snapshot/deleter.rb0000644000076400007640000000506612511713252021535 0ustar pravipravimodule Fission module Action module Snapshot class Deleter # Internal: Creates a new SnapshotDeleter object. This accepts a VM # object. # # vm - An instance of VM # # Examples: # # Fission::Action::SnapshotDeleter.new @my_vm # # Returns a new SnapshotDeleter object def initialize(vm) @vm = vm end # Public: Deletes a snapshot for a VM. The snapshot to delete must # exist. If the Fusion GUI is running, then the VM must also be running. # # name - The name of the snapshot to delete. # # Examples # # @deleter.delete_snapshot('foo_snap_1') # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def delete_snapshot(name) unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end if Fusion.running? running_response = @vm.running? return running_response unless running_response.successful? unless running_response.data message = 'A snapshot cannot be deleted when the GUI is running ' message << 'and the VM is not running.' return Response.new :code => 1, :message => message end end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? snapshots_response = @vm.snapshots return snapshots_response unless snapshots_response.successful? unless snapshots_response.data.include? name message = "Unable to find a snapshot named '#{name}'." return Response.new :code => 1, :message => message end command = "#{vmrun_cmd} deleteSnapshot " command << "'#{conf_file_response.data}' \"#{name}\" 2>&1" command_exec = Fission::Action::ShellExecutor.new command Response.from_shell_executor command_exec.execute end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @deleter.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/snapshot/lister.rb0000644000076400007640000000503112511713252021403 0ustar pravipravimodule Fission module Action module Snapshot class Lister # Internal: Creates a new SnapshotLister object. This accepts a VM # object. # # vm - An instance of VM # # Examples: # # Fission::Action::SnapshotLister.new @my_vm # # Returns a new SnapshotLister object def initialize(vm) @vm = vm end # Internal: List the snapshots for a VM. # # Examples # # @lister.snapshots.data # # => ['snap 1', 'snap 2'] # # Returns a Response with the result. # If successful, the Repsonse's data attribute will be an Array of the # snapshot names (String). # If there is an error, an unsuccessful Response will be returned. def snapshots unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? command = "#{vmrun_cmd} listSnapshots " command << "'#{conf_file_response.data}' 2>&1" command_exec = Fission::Action::ShellExecutor.new command result = command_exec.execute response = Response.new :code => result['process_status'].exitstatus if response.successful? response.data = parse_snapshot_names_from_output result['output'] else response.message = result['output'] end response end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @lister.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end # Internal: Parses the output of the listSnapshot command. # # output - The output of the vmrun listSnapshot command. # # Examples: # @lister.parse_snapshot_names_from_output cmd_output # # => ['snap_1', 'snap_2'] # # Returns an Array with the list of snapshot names. def parse_snapshot_names_from_output(cmd_output) header_text = 'Total snapshots:' snaps = cmd_output.split("\n").select { |s| !s.include? header_text } snaps.map { |s| s.strip } end end end end end fission-0.5.0/lib/fission/action/snapshot/reverter.rb0000644000076400007640000000475312511713252021751 0ustar pravipravimodule Fission module Action module Snapshot class Reverter # Internal: Creates a new SnapshotReverter object. This accepts a VM # object. # # vm - An instance of VM # # Examples: # # Fission::Action::SnapshotReverter.new @my_vm # # Returns a new SnapshotReverter object def initialize(vm) @vm = vm end # Public: Reverts the VM to the specified snapshot. The snapshot to # revert to must exist and the Fusion GUI must not be running. # # name - The snapshot name to revert to. # # Examples # # @reverter.revert_to_snapshot('foo_snap_1') # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def revert_to_snapshot(name) unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end if Fusion.running? message = 'It looks like the Fusion GUI is currently running. ' message << 'A VM cannot be reverted to a snapshot when the Fusion GUI is running. ' message << 'Exit the Fusion GUI and try again.' return Response.new :code => 1, :message => message end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? snapshots_response = @vm.snapshots return snapshots_response unless snapshots_response.successful? unless snapshots_response.data.include? name message = "Unable to find a snapshot named '#{name}'." return Response.new :code => 1, :message => message end command = "#{vmrun_cmd} revertToSnapshot " command << "'#{conf_file_response.data}' \"#{name}\" 2>&1" command_exec = Fission::Action::ShellExecutor.new command Response.from_shell_executor command_exec.execute end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @reverter.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of # Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/action/snapshot/creator.rb0000644000076400007640000000470012511713252021542 0ustar pravipravimodule Fission module Action module Snapshot class Creator # Internal: Creates a new SnapshotCreator object. This accepts a VM # object. # # vm - An instance of VM # # Examples: # # Fission::Action::SnapshotCreator.new @my_vm # # Returns a new SnapshotCreator object def initialize(vm) @vm = vm end # Public: Creates a snapshot for a VM. The VM must be running in order # to create a snapshot. Snapshot names must be unique. # # name - The desired name of the snapshot. The name must be unique. # # Examples # # @creator.create_snapshot('foo_snap_1') # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def create_snapshot(name) unless @vm.exists? return Response.new :code => 1, :message => 'VM does not exist' end running_response = @vm.running? return running_response unless running_response.successful? unless running_response.data message = 'The VM must be running in order to take a snapshot.' return Response.new :code => 1, :message => message end conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? snapshots_response = @vm.snapshots return snapshots_response unless snapshots_response.successful? if snapshots_response.data.include? name message = "There is already a snapshot named '#{name}'." return Response.new :code => 1, :message => message end command = "#{vmrun_cmd} snapshot " command << "'#{conf_file_response.data}' \"#{name}\" 2>&1" command_exec = Fission::Action::ShellExecutor.new command Response.from_shell_executor command_exec.execute end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @creator.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end end end fission-0.5.0/lib/fission/response.rb0000644000076400007640000000543012511713252016626 0ustar pravipravimodule Fission class Response # Public: Gets/Sets the code (Integer). attr_accessor :code # Public: Gets/Sets the message (String). attr_accessor :message # Public: Gets/Sets the data (can be any of type as needed). attr_accessor :data # Public: Initialize a Response object. # # args - Hash of arguments: # :code - Integer which denotes the code of the Response. This is # similar in concept to command line exit codes. The # convention is that 0 denotes success and any other value # is unsuccessful (default: 1). # :message - String which denotes the message of the Response. The # convention is that this should only be used when the # Response is unsuccessful (default: ''). # :data - Any valid ruby object. This is used to convey any # data that needs to be used by a caller. The convention # is that this should only be used when the Response is # successful (default nil). # # Examples # # Response.new :code => 0, :data => [1, 2, 3, 4] # # Response.new :code => 0, :data => true # # Response.new :code => 5, :message => 'Something went wrong' # # Returns a new Response instance. def initialize(args={}) @code = args.fetch :code, 1 @message = args.fetch :message, '' @data = args.fetch :data, nil end # Public: Helper method to determine if a response is successful or not. # # Examples # # response.successful? # # => true # # response.successful? # # => false # # Returns a Boolean. # Returns true if the code is 0. # Returns false if the code is any other value. def successful? @code == 0 end # Internal: Helper method to create a new Response object when using # executing a command through Fission::Action::ShellExecutor. # # shell_execute_result - This should be the result of running 'execute' on # a ShellExecutor object. # # Examples: # # Response.from_shell_executor shell_execute_result # # Returns a Response. # The code attribute of the Response will be set to the exit_status # attribute of the provided process_status data. The message attribute of # the Response will be set to the output of the provided data if, and only # if, the Response is unsuccessful. def self.from_shell_executor(shell_execute_result) response = new :code => shell_execute_result['process_status'].exitstatus unless response.successful? response.message = shell_execute_result['output'] end response end end end fission-0.5.0/lib/fission/command_line_parser.rb0000644000076400007640000001177112511713252020776 0ustar pravipravimodule Fission class CommandLineParser # Internal: Creates a new Fission::CommandLineParser object. # # args - The command line arguments to parse. This is expected to be in the # same format of ARGV (Array) (default: ARGV). # # Examples: # # CommandLineParser.new ['foo', 'bar'] # # CommandLineParser.new # # Returns a Fission::CommandLineParser object. def initialize(args=ARGV) @args = args gather_commands_and_summaries setup_options_parser end # Internal: Parses the command line arguments. If the arguments are # invalid, the appropriate help will be output and then will exit. If the # arguments are valid, then the @command variable will be set to a new # instance of the determined command class. # # Examples: # # @command_line_parser.parse # # Returns nothing. def parse @options_parser.order! @args determine_command_provided self rescue OptionParser::InvalidOption => e ui.output e show_all_help exit 1 end # Internal: Accessor for an instance of the determined command. This is set # by running the parse method. # # Examples: # # @command_line_parser.command # # Returns an instance of the determined command if the arguments are valid. # Returns nil if the parse command has not yet been run. def command @command end private # Internal: Sets up the base option parser. # # Examples: # # @cli.setup_option_parser # # Returns nothing. This will set the @option_parser instance variable. def setup_options_parser @options_parser = OptionParser.new do |opts| opts.banner = "\nUsage: fission [options] COMMAND [arguments]" opts.on_head('-v', '--version', 'Output the version of fission') do ui.output VERSION exit 0 end opts.on_head('-h', '--help', 'Displays this message') do show_all_help exit 0 end end end # Internal: Provides the help of all of the known commands. # # Examples # # @cli.commands_help # # Outputs the summary text for all known commands. def commands_help longest_cmd = @commands.inject do |longest, cmd_name| longest.length > cmd_name.length ? longest : cmd_name end ui.output "\nCommands:" Hash[@command_names_and_summaries.sort].each_pair do |name, summary| ui.output_printf "%-#{longest_cmd.length}s %s\n", name, summary end end # Internal: Determines all of the available commands and their summaries. # # Examples # # @cli.command_names_and_summaries # # => { 'clone' => 'Clones a VM', 'stop' => 'Stops a VM' } # # Returns nothing. This will set the @command_names_and_summaries instance # variable with the result. def gather_commands_and_summaries @command_names_and_summaries = Command.descendants.inject({}) do |result, klass| cmd = klass.new result[cmd.command_name] = cmd.summary result end @commands = @command_names_and_summaries.keys.sort end # Internal: Determines the command that has been provided. If it is # determined that an invalid command is provided, then the help/usage will # be displayed and it will exit. # # Examples: # # @cli.determine_command_to_execute # # Returns nothing. This will set the @command instance variable to an instance # of the appropriate command class (assuming it is valid). def determine_command_provided if @commands.include? @args.first @command = Command.const_get(@args.first.capitalize).new @args.drop 1 elsif is_snapshot_command? klass = @args.take(2).map {|c| c.capitalize}.join('') @command = Command.const_get(klass).new @args.drop 2 else show_all_help exit 1 end end # Internal: Determines if the provided command is a snapshot related # command. This will use the @args instance variable to make the # determination. # # Examples # # @cli.is_snapshot_command? ['foo', 'bar'] # # => false # # @cli.is_snapshot_command? ['snapshot', 'list'] # # => true # # Returns a Boolean of whether a snapshot command was given or not. def is_snapshot_command? @args.first == 'snapshot' && @args.count > 1 && @commands.include?(@args.take(2).join(' ')) end # Internal: Outputs the usage as well as the known commands and their # summaries. # # Examples # # @cli.show_all_help # # => 'fission options command arguments ....' # # Returns nothing. def show_all_help ui.output @options_parser commands_help end # Internal: Helper method for outputting text to the ui # # Examples # # @cli.ui.output 'foo' # # Returns a UI instance. def ui @ui ||= UI.new end end end fission-0.5.0/lib/fission/metadata.rb0000644000076400007640000000565212511713252016556 0ustar pravipravimodule Fission class Metadata require 'cfpropertylist' # Public: Gets/Sets the content (Hash). attr_accessor :content # Public: Deletes the Fusion metadata related to a VM. The VM should not be # running when this method is called. It's highly recommended to call this # method without the Fusion GUI application running. If the Fusion GUI is # running this method should succeed, but it's been observed that Fusion # will recreate the metadata which is deleted. This leads to 'missing' VMs # in the Fusion GUI. # # vm_path - The absolute path to the directory of a VM. # # Examples # # Fission::Metadata.delete_vm_info '/vms/foo.vmwarevm' # # Returns nothing. def self.delete_vm_info(vm_path) metadata = new metadata.load metadata.delete_vm_restart_document(vm_path) metadata.delete_vm_favorite_entry(vm_path) metadata.save end # Public: Reads the configured metadata file and populates the content # variable with native ruby types. # # Examples # # metadata.load # # Returns nothing. def load raw_data = CFPropertyList::List.new :file => Fission.config['plist_file'] @content = CFPropertyList.native_types raw_data.value end # Public: Saves a new version of the metadata file with the data in the # content variable. # # Examples # # metadata.save # # Returns nothing. def save new_content = CFPropertyList::List.new new_content.value = CFPropertyList.guess @content new_content.save Fission.config['plist_file'], CFPropertyList::List::FORMAT_BINARY end # Public: Deletes the VM information from the 'restart document path' # metadata. The 'restart document path' dictates which GUI consoles to # display when Fusion starts. # # vm_path - The absolute path to the directory of a VM. # # Examples # # metadata.delete_vm_restart_document 'vms/foo.vmwarevm' # # Returns nothing. def delete_vm_restart_document(vm_path) if @content.has_key?('PLRestartDocumentPaths') @content['PLRestartDocumentPaths'].delete_if { |p| p == vm_path } end end # Public: Deletes the VM information from the 'favorites list' metadata. # The 'favorites list' dictates which VMs are displayed in the Fusion VM # libarary. # # vm_path - The absolute path to the directory of a VM. # # Examples # # metadata.delete_favorite_entry '/vms/foo.vmwarevm' # # Returns nothing. def delete_vm_favorite_entry(vm_path) if @content.has_key?('VMFavoritesListDefaults2') @content['VMFavoritesListDefaults2'].delete_if { |vm| vm['path'] == vm_path } end if @content.has_key?('fusionInitialSessions') @content['fusionInitialSessions'].delete_if {|vm| vm['documentPath'] == vm_path} end end end end fission-0.5.0/lib/fission/fusion.rb0000644000076400007640000000074512511713252016277 0ustar pravipravimodule Fission class Fusion # Public: Determines if the VMware Fusion GUI application is running. # # Examples # # Fission::Fusion.running? # # => true # # Returns a Boolean. def self.running? command = "ps -ef | grep -v grep | grep -c " command << "'#{Fission.config['gui_bin']}' 2>&1" command_executor = Fission::Action::ShellExecutor.new command command_executor.execute['output'].strip.to_i > 0 end end end fission-0.5.0/lib/fission/version.rb0000644000076400007640000000004712511713252016454 0ustar pravipravimodule Fission VERSION = "0.5.0" end fission-0.5.0/lib/fission/lease.rb0000644000076400007640000001002412511713252016054 0ustar pravipravimodule Fission class Lease # Public: Get/set the IP address for the lease. attr_accessor :ip_address # Public: Get/set the MAC address for the lease. attr_accessor :mac_address # Public: Get/set the start DateTime for the lease. attr_accessor :start # Public: Get/set the end DateTime for the lease. attr_accessor :end # Public: Initialize a Lease object. # # args - Hash of arguments: # :ip_address - String which denotes the IP address of the lease. # :mac_address - String which denotes the MAC address of the lease. # :start - DateTime which denotes the start of the lease. # :end - DateTime which denotes the end of the lease. # # Examples # # Returns a new Lease instance. def initialize(args={}) @ip_address = args[:ip_address] @mac_address = args[:mac_address] @start = args[:start] @end = args[:end] end # Public: Determine if the lease has expired or not. # # Examples: # # @lease.expired? # # => true # # Returns a Boolean. The Boolean is determined by comparing the end # attribute to the current date/time. def expired? @end < DateTime.now end # Public: Provides all of the known leases. # # Examples: # # Fission::Lease.all # # => [#, # #] # # Returns a Response with the result. # If successful, the Response's data attribute will be an Array of Lease # objects. If no leases are found, then the Response's data attribute will # be an empty Array. # If there is an error, an unsuccessful Response will be returned. def self.all response = Response.new if File.file? Fission.config['lease_file'] content = File.read Fission.config['lease_file'] response.data = content.split('}').collect do |entry| parse entry end content = nil response.code = 0 else response.code = 1 response.message = "Unable to find the lease file '#{Fission.config['lease_file']}'" end response end # Public: Get lease information for a specific MAC address. # # mac_address - MAC address (String) to search for. # # Examples # # Fission::Lease.find_by_mac '00:11:AA:bb:cc:22' # # => # # # Returns a Response with the result. # If successful, the Response's data attribute will be a Lease object if the # MAC address was found. The Response's data attribute will be nil if the # MAC address was not found. # If there is an error, an unsuccessful Response will be returned. def self.find_by_mac_address(mac_address) all_response = all if all_response.successful? response = Response.new :code => 0 leases = all_response.data.find_all { |l| l.mac_address == mac_address } response.data = leases.sort_by { |l| l.end }.last else response = all_response end response end private # Internal: Parses information out of a DHCP lease entry. # # entry - String of lease entry text. # # Examples # # Lease.parse my_lease_entry # # => # # # # Returns a Lease object which is populated with the attribute that were # found. def self.parse(lease_entry) lease = Lease.new lease_entry.gsub! ';', '' lease_entry.split("\n").each do |line| next if line =~ /^#/ line.strip! case line.strip when /^lease/ lease.ip_address = line.split(' ')[1] when /^starts/ lease.start = DateTime.parse(line.split(' ')[2..3].join(' ')) when /^end/ lease.end = DateTime.parse(line.split(' ')[2..3].join(' ')) when /^hardware/ lease.mac_address = line.split(' ')[2] end end lease end end end fission-0.5.0/lib/fission/vm.rb0000644000076400007640000004705712511713252015425 0ustar pravipravimodule Fission class VM # Public: Gets the name of the VM as a String. attr_reader :name def initialize(name) @name = name end # Public: Creates a snapshot for a VM. The VM must be running in order # to create a snapshot. Snapshot names must be unique. # # name - The desired name of the snapshot. The name must be unique. # # Examples # # @vm.create_snapshot('foo_snap_1') # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def create_snapshot(name) Fission::Action::Snapshot::Creator.new(self).create_snapshot(name) end # Public: Deletes a snapshot for a VM. The snapshot to delete must exist. # If the Fusion GUI is running, then the VM must also be running. # # name - The name of the snapshot to delete. # # Examples # # @vm.delete_snapshot('foo_snap_1') # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def delete_snapshot(name) Fission::Action::Snapshot::Deleter.new(self).delete_snapshot(name) end # Public: Reverts the VM to the specified snapshot. The snapshot to revert # to must exist and the Fusion GUI must not be running. # # name - The snapshot name to revert to. # # Examples # # @vm.revert_to_snapshot('foo_snap_1') # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def revert_to_snapshot(name) Fission::Action::Snapshot::Reverter.new(self).revert_to_snapshot(name) end # Public: List the snapshots for a VM. # # Examples # # @vm.snapshots.data # # => ['snap 1', 'snap 2'] # # Returns a Response with the result. # If successful, the Repsonse's data attribute will be an Array of the # snapshot names (String). # If there is an error, an unsuccessful Response will be returned. def snapshots Fission::Action::Snapshot::Lister.new(self).snapshots end # Public: Deletes a VM. The VM must not be running in order to delete it. # As there are a number issues with the Fusion command line tool for # deleting VMs, this is a best effort. The VM must not be running when this # method is called. This essentially deletes the VM directory and attempts # to remove the relevant entries from the Fusion plist file. It's highly # recommended to delete VMs without the Fusion GUI running. If the Fusion # GUI is running this method should succeed, but it's been observed that # Fusion will recreate the plist data which is deleted. This leads to # 'missing' VMs in the Fusion GUI. # # Examples # # @vm.delete # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def delete Fission::Action::VM::Deleter.new(self).delete end # Public: Starts a VM. The VM must not be running in order to start it. # # options - Hash of options: # :headless - Boolean which specifies to start the VM without a # GUI console. The Fusion GUI must not be running in # order to start the VM headless. # (default: false) # # Examples # # @vm.start # # @vm.start :headless => true # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def start(options={}) Fission::Action::VM::Starter.new(self).start(options) end # Public: Stops a VM. The VM must be running in order to stop it. # # options - Hash of options: # :hard - Boolean which specifies to power off the VM (instead of # attempting to initiate a graceful shutdown). This is # the equivalent of passing 'hard' to the vmrun stop # command. # (default: false) # # Examples # # @vm.stop # # @vm.stop :hard => true # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def stop(options={}) Fission::Action::VM::Stopper.new(self).stop(options) end # Public: Suspends a VM. The VM must be running in order to suspend it. # # Examples # # @vm.suspend # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def suspend Fission::Action::VM::Suspender.new(self).suspend end # Public: Provides virtual hardware info the VM # # Examples: # # @vm.hardware_info.data # # => {'cpus' => 2, 'memory' => 1024} # # Returns a Response with the result. # If successful, the Response's data attribute will be a Hash with the # info found. # If there is an error, an unsuccessful Response will be returned. def hardware_info config_response = conf_file_data return config_response unless config_response.successful? response = Response.new :code => 0, :data => {} response.data['cpus'] = 1 { 'cpus' => 'numvcpus', 'memory' => 'memsize' }.each_pair do |k,v| unless config_response.data[v].blank? response.data[k] = config_response.data[v].to_i end end response end # Public: Provides the MAC addresses for a VM. # # Examples: # # @vm.mac_addresses.data # # => ['00:0c:29:1d:6a:64', '00:0c:29:1d:6a:75'] # # Returns a Response with the result. # If successful, the Response's data attribute will be an Array of the MAC # addresses found. If no MAC addresses are found, the Response's data # attribute will be an empty Array. # If there is an error, an unsuccessful Response will be returned. def mac_addresses network_response = network_info return network_response unless network_response.successful? response = Response.new :code => 0 response.data = network_response.data.values.collect { |n| n['mac_address'] } response end # Public: Network information for a VM. Includes interface name, associated # MAC address, and IP address (if applicable). # # Examples: # # # if IP addresses are found in the Fusion DHCP lease file # response = @vm.network_info.data # # => { 'ethernet0' => { 'mac_address' => '00:0c:29:1d:6a:64', # 'ip_address' => '127.0.0.1' }, # 'ethernet1' => { 'mac_address' => '00:0c:29:1d:6a:75', # 'ip_address' => '127.0.0.2' } } # # # if IP addresses are not found in the Fusion DHCP lease file # response = @vm.network_info.data # # => { 'ethernet0' => { 'mac_address' => '00:0c:29:1d:6a:64', # 'ip_address' => nil }, # 'ethernet1' => { 'mac_address' => '00:0c:29:1d:6a:75', # 'ip_address' => nil } } # # Returns a Response with the result. # If successful, the Response's data attribute will be a Hash with the # interface identifiers as the keys and the associated MAC address. If an # IP address was found in the Fusion DHCP lease file, then it will # be included. If an IP address was not found, then the IP address value # will be nil. If there are no network interfaces, the Response's data # attribute will be an empty Hash. # If there is an error, an unsuccessful Response will be returned. def network_info config_response = conf_file_data return config_response unless config_response.successful? response = Response.new :code => 0, :data => {} interface_pattern = /^ethernet\d+/ mac_pattern = /(\w\w[:-]\w\w[:-]\w\w[:-]\w\w[:-]\w\w[:-]\w\w)/ config_response.data.each_pair do |k,v| if v =~ mac_pattern mac = v int = k.scan(interface_pattern).first response.data[int] = { 'mac_address' => mac } lease_response = Fission::Lease.find_by_mac_address mac return lease_response unless lease_response.successful? response.data[int]['ip_address'] = nil if lease_response.data response.data[int]['ip_address'] = lease_response.data.ip_address end end end response end # Public: Provides the Fussion GuestOS profile. # # Examples # # @vm.guestos.data # # => 'debian5' # # Returns a Response with the result. # If the Response is successful, the Response's data attribute will # be populated with a string that is the guest operatingsystem used for the # virtual machine. # If there is an error, an unsuccessful Response will be returned. def guestos config_response = conf_file_data return config_response unless config_response.successful? response = Response.new :code => 0, :data => {} response.data = config_response.data.fetch 'guestOS', '' response end # Public: Provides various uuids associated with a VM. # # Examples # # @vm.uuids.data # # => {"bios"=>"56 4d ee 72 3b 7e 47 67-69 aa 65 cb 5e 40 3f 21", # "location"=>"56 4d 2e 15 f4 ed 00 a7-c5 99 43 32 b8 76 ef d5"} # # Returns a Response with the result. # If the Response is successful, the Response's data attribute will # be populated with a hash that is comprised of the various uuids that are # associated with each VM. If the VM is newly created they will be the same # but if you selected 'I Moved It' from the Fusion GUI they will differ. # If there is an error, an unsuccessful Response will be returned. def uuids config_response = conf_file_data return config_response unless config_response.successful? response = Response.new :code => 0, :data => {} { 'bios' => 'uuid.bios', 'location' => 'uuid.location' }.each_pair do |k,v| unless config_response.data[v].blank? response.data[k] = config_response.data[v] end end response end # Public: Provides the state of the VM. # # Examples # # @vm.state.data # # => 'running' # # @vm.state.data # # => 'not running' # # @vm.state.data # # => 'suspended' # # Returns a Response with the result. # If the Response is successful, the Response's data attribute will # be a String of the state. If the VM is currently powered on, the state # will be 'running'. If the VM is deemed to be suspended, the state will be # 'suspended'. If the VM is not running and not deemed to be suspended, the # state will be 'not running'. # If there is an error, an unsuccessful Response will be returned. def state running_response = running? return running_response unless running_response.successful? response = Response.new :code => 0, :data => 'not running' if running_response.data response.data = 'running' else suspended_response = suspended? return suspended_response unless suspended_response.successful? response.data = 'suspended' if suspended_response.data end response end # Public: Determines if the VM exists or not. This method looks for the # VM's conf file ('.vmx') to determine if the VM exists or not. # # Examples # # @vm.exists? # # => true # # Returns a Boolean. def exists? conf_file.successful? end # Public: Determines if a VM is suspended. # # Examples # # @vm.suspended?.data # # => true # # Returns a Response with the result. # If successful, the Response's data attribute will be a Boolean. If the VM # is not running, then this method will look for a '.vmem' file in the VM's # directory. If a '.vmem' file exists and it matches the name of the VM, # then the VM is considered to be suspended. If the VM is running or if a # matching '.vmem' file is not found, then the VM is not considered to be # suspended. # If there is an error, an unsuccessful Response will be returned. def suspended? running_response = running? return running_response unless running_response.successful? response = Response.new :code => 0, :data => false response.data = suspend_file_exists? unless running_response.data response end # Public: Determines if a VM has a suspend file ('.vmem') in it's directory. # This only looks for a suspend file which matches the name of the VM. # # Examples # # @vm.suspend_file_exists? # # => true # # Returns a Boolean. def suspend_file_exists? File.file? File.join(path, "#{@name}.vmem") end # Public: Determines if a VM is running. # # Examples # # @vm.running?.data # # => true # # Returns a Response with the result. # If successful, the Response's data attribute will be a Boolean. # If there is an error, an unsuccessful Response will be returned. def running? all_running_response = self.class.all_running return all_running_response unless all_running_response.successful? response = Response.new :code => 0, :data => false if all_running_response.data.collect { |v| v.name }.include? @name response.data = true end response end # Public: Provides the configuration data stored in the VM's configuration # file ('.vmx'). # # Examples # # @vm.conf_file_data # # Returns a Response with the result. # If successful, the Response's data attribute with be a Hash of the # configuration data. All of the keys/values in the configuration data will # be a String. # If there is an error, an unsuccessful Response will be returned. def conf_file_data VMConfiguration.new(self).config_data end # Public: Determines the path to the VM's config file ('.vmx'). # # Examples # # @vm.conf_file.data # # => '/my_vms/foo/foo.vmx' # # Returns a Response with the result. # If successful, the Response's data attribute will be a String which will # be escaped for spaces (' '). # If there is a single '.vmx' file in the VM's directory, regardless if # the name of '.vmx' file matches the VM name, the Response's data # attribute will the be the path to the '.vmx' file. # If there are multiple '.vmx' files found in the VM's directory, there are # a couple of different possible outcomes. # If one of the file names matches the VM directory name, then the # Response's data attribute will be the path to the matching '.vmx' file. # If none of the file names match the VM directory name, then this is deemed # an error condition and an unsuccessful Response will be returned. # If there is an error, an unsuccessful Response will be returned. def conf_file vmx_path = File.join path, "*.vmx" conf_files = Dir.glob vmx_path response = Response.new case conf_files.count when 0 response.code = 1 response.message = "Unable to find a config file for VM '#{@name}' (in '#{vmx_path}')" when 1 response.code = 0 response.data = conf_files.first else if conf_files.include?(File.join(File.dirname(vmx_path), "#{@name}.vmx")) response.code = 0 response.data = File.join(File.dirname(vmx_path), "#{@name}.vmx") else response.code = 1 output = "Multiple config files found for VM '#{@name}' (" output << conf_files.sort.map { |f| "'#{File.basename(f)}'" }.join(', ') output << " in '#{File.dirname(vmx_path)}')" response.message = output end end response end # Public: Provides the expected path to a VM's directory. This does not # imply that the VM or path exists. # # name - The name of the VM to provide the path for. # # Examples # # @vm.path # # => '/vm/foo.vmwarevm' # # Returns the path (String) to the VM's directory. def path File.join Fission.config['vm_dir'], "#{@name}.vmwarevm" end # Public: Provides all of the VMs which are located in the VM directory. # # Examples # # Fission::VM.all.data # # => [, # ] # # Returns a Response with the result. # If successful, the Response's data attribute will be an Array of VM # objects. If no VMs are found, the Response's data attribute will be an # empty Array. # If there is an error, an unsuccessful Response will be returned. def self.all Fission::Action::VM::Lister.new.all end # Public: Provides all of the VMs which are currently running. # # Examples # # Fission::VM.all_running.data # # => [, # ] # # Returns a Response with the result. # If successful, the Response's data attribute will be an Array of VM # objects which are running. If no VMs are running, the Response's data # attribute will be an empty Array. # If there is an error, an unsuccessful Response will be returned. def self.all_running Fission::Action::VM::Lister.new.all_running end # Public: Provides a list of all of the VMs and their associated status # # Examples # # Fission::VM.all_with_status.data # # => { 'vm1' => 'running', 'vm2' => 'suspended', 'vm3' => 'not running'} # # Returns a Response with the result. # If successful, the Response's data attribute will be a Hash of with the VM # names as keys and their status as the values. # If there is an error, an unsuccessful Repsonse will be returned. def self.all_with_status Fission::Action::VM::Lister.new.all_with_status end # Public: Creates a new VM which is a clone of an existing VM. As Fusion # doesn't provide a native cloning mechanism, this is a best effort. This # essentially is a directory copy with updates to relevant files. It's # recommended to clone VMs which are not running. # # source_vm_name - The name of the VM to clone. # target_vm_name - The name of the VM to be created. # # Examples # # Fission::VM.clone 'foo', 'bar' # # Returns a Response with the result. # If successful, the Response's data attribute will be nil. # If there is an error, an unsuccessful Response will be returned. def self.clone(source_vm_name, target_vm_name) @source_vm = new source_vm_name @target_vm = new target_vm_name Fission::Action::VM::Cloner.new(@source_vm, @target_vm).clone end private # Internal: Helper for getting the configured vmrun_cmd value. # # Examples # # @vm.vmrun_cmd # # => "/foo/bar/vmrun -T fusion" # # Returns a String for the configured value of Fission.config['vmrun_cmd']. def vmrun_cmd Fission.config['vmrun_cmd'] end end end fission-0.5.0/lib/fission/config.rb0000644000076400007640000000336012511713252016235 0ustar pravipravimodule Fission class Config # Public: Gets/Sets the Hash of attributes. attr_accessor :attributes # Public: Path to the Fission conf file (default: ~/.fissionrc). CONF_FILE = File.expand_path '~/.fissionrc' # Public: Initializes a Config object. This also sets the default config # attributes for 'vmrun_bin', 'vmrun_cmd', 'vm_dir', 'plist_file', and # 'gui_bin'. # # Examples # # Fission::Config.new # # Returns a new Config instance. def initialize @attributes = {} @attributes['vm_dir'] = File.expand_path('~/Documents/Virtual Machines.localized/') @attributes['lease_file'] = '/var/db/vmware/vmnet-dhcpd-vmnet8.leases' @attributes['vmrun_bin'] = '/Library/Application Support/VMware Fusion/vmrun' @attributes['plist_file'] = File.expand_path('~/Library/Preferences/com.vmware.fusion.plist') @attributes['gui_bin'] = File.expand_path('/Applications/VMware Fusion.app/Contents/MacOS/vmware') load_from_file @attributes['vmrun_cmd'] = "'#{@attributes['vmrun_bin']}' -T fusion" end # Public: Helper method to access config atributes. This is a shortcut for # querying the config attributes. # # item - The config item to query. # # Examples # # Fission.config['vmrun_bin'] # # => '/foo/bar/vmrun' # # Returns the value of the specified config item. def [](item) @attributes[item] end private # Internal: Loads config values from the Fission conf file into attributes. # # Examples # # load_from_file # # Returns nothing. def load_from_file if File.file?(CONF_FILE) @attributes.merge!(YAML.load_file(CONF_FILE)) end end end end fission-0.5.0/lib/fission/command_helpers.rb0000644000076400007640000000153612511713252020133 0ustar pravipravimodule Fission module CommandHelpers # Internal: Outputs the help text for a command and exits. # # Examples # # incorrect_arguments # # Returns nothing. # This will call the help class method for the help text. This will exit # with the exit code 1. def incorrect_arguments output "#{self.class.help}\n" output_and_exit "Incorrect arguments for #{command_name} command", 1 end # Internal: Parses the command line arguments. # # Examples: # # parse_arguments # # Returns nothing. # If there is an invalid argument, an error will be output and this will # exit with exit code 1. def parse_arguments option_parser.parse! @args rescue OptionParser::InvalidOption => e output e output_and_exit "\n#{self.class.help}", 1 end end end fission-0.5.0/lib/fission/vm_configuration.rb0000644000076400007640000000504112511713252020337 0ustar pravipravimodule Fission class VMConfiguration # Internal: Creates a new VMConfiguration object. This accepts a VM object # # vm - An instance of VM # # Examples: # # Fission::VMConfiguration.new @my_vm # # Returns a new VMConfiguration object def initialize(vm) @vm = vm end # Internal: Gathers the the configuration data for the VM. This essentially # parses the key/value pairs from the configuration file (.vmx) into a Hash. # # Exaples: # # @vm_config.config_data.data # # => { 'memsize' => '384', 'ethernet0.present' => 'TRUE',... } # # Returns a Response object with the result. # If successful, the Response's data attribute will be a Hash. All keys and # values are represented as a String (even when the value in the # configuration file is 'TRUE'). If a value is an empty string in the # configuration file, it will be represented in the Hash as an empty String. # If there is an error, an unsuccessful Response will be returned. def config_data return Response.new :code => 1, :message => 'VM does not exist' unless @vm.exists? conf_file_response = @vm.conf_file return conf_file_response unless conf_file_response.successful? @conf_file_location = conf_file_response.data Response.new :code => 0, :data => parse_vm_config_file end private # Internal: Parses the configuration file (i.e. '.vmx') # # Examples: # # @vm_config.parse_vm_config_file # # => { 'memsize' => '384', 'ethernet0.present' => 'TRUE',... } # # Returns a Hash. # All keys and values are represented as a String (even when the value in # the conf file is 'TRUE'). If a value is an empty string in the # configuration file, it will be represented in the Hash as an empty String. def parse_vm_config_file File.readlines(@conf_file_location).inject({}) do |result, line| data = parse_line_data(line) result[data[0]] = (data[1].nil? ? '' : data[1]) result end end # Internal: Splits and formats a single line from a VM configuration file # into an Array. # # Examples: # # @vm_config.parse_line_data('foo = "bar"') # # Returns an Array. The first item will be the left side of the '=' and the # second item will be the right side. This will also strip any whitespace # characters from the beginning or end of the provided line. def parse_line_data(line) line.strip.gsub('"', '').split ' = ' end end end fission-0.5.0/lib/fission/ui.rb0000644000076400007640000000335412511713252015410 0ustar pravipravimodule Fission class UI # Internal: Returns the stdout value. attr_reader :stdout # Internal: Initialize a UI object. # # stdout - The object to use for stdout (default: $stdout). This provides # an easy way to capture/silence output if needed. # # Examples # # Fission::UI.new # # str_io = StringIO.new # Fission::UI.new str_io def initialize(stdout=$stdout) @stdout = stdout end # Internal: Outputs the specified argument to the configured stdout object. # The 'puts' method will be called on the stdout object. # # s - The String to output. # # Examples # # ui.output "foo bar\n" # # Returns nothing. def output(s) @stdout.puts s end # Internal: Outputs the specified arguments printf style. The 'printf' # method will be called on the stdout object. Currently, this assuems there # are two data items. # # string - The printf String. # key - The String for the first data item. # value - The String for the second data item. # # Examples # # ui.output_printf "%s %s\n", 'foo', bar # # Returns nothing. def output_printf(string, key, value) @stdout.send :printf, string, key, value end # Internal: Outputs the specified argument to the configured stdout object # and exits with the specified exit code. # # s - The String to output. # exit_code - The Integer exit code. # # Examples # # ui.output_and_exit 'something went wrong', 99 # # ui.output_and_exit 'all done', 0 # # Returns nothing. def output_and_exit(s, exit_code) output s exit exit_code end end end fission-0.5.0/lib/fission/command/0000755000076400007640000000000012511713252016057 5ustar pravipravifission-0.5.0/lib/fission/command/stop.rb0000644000076400007640000000140612511713252017372 0ustar pravipravimodule Fission class Command class Stop < Command def execute super incorrect_arguments unless @args.count == 1 vm = VM.new @args.first output "Stopping '#{vm.name}'" response = vm.stop if response.successful? output "VM '#{vm.name}' stopped" else output_and_exit "There was an error stopping the VM. The error was:\n#{response.message}", response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission stop TARGET_VM" opts.separator '' opts.separator 'Stop TARGET_VM.' end optparse end def summary 'Stop a VM' end end end end fission-0.5.0/lib/fission/command/snapshot_list.rb0000644000076400007640000000166012511713252021301 0ustar pravipravimodule Fission class Command class SnapshotList < Command def execute super incorrect_arguments unless @args.count == 1 vm = VM.new @args.first response = vm.snapshots if response.successful? snaps = response.data if snaps.any? output snaps.join("\n") else output "No snapshots found for VM '#{vm.name}'" end else output_and_exit "There was an error listing the snapshots. The error was:\n#{response.message}", response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission snapshot list TARGET_VM" opts.separator '' opts.separator 'Lists all of the snapshots for TARGET_VM' end optparse end def summary 'List the snapshots of a VM' end end end end fission-0.5.0/lib/fission/command/suspend.rb0000644000076400007640000000275012511713252020071 0ustar pravipravimodule Fission class Command class Suspend < Command def initialize(args=[]) super @options.all = false end def execute super incorrect_arguments if @args.count != 1 && !@options.all vms_to_suspend.each do |vm| output "Suspending '#{vm.name}'" response = vm.suspend if response.successful? output "VM '#{vm.name}' suspended" else output_and_exit "There was an error suspending the VM. The error was:\n#{response.message}", response.code end end end def vms_to_suspend if @options.all response = VM.all_running if response.successful? vms = response.data else output_and_exit "There was an error getting the list of running VMs. The error was:\n#{response.message}", response.code end else vms = [ VM.new(@args.first) ] end vms end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission suspend [TARGET_VM | --all]" opts.separator '' opts.separator 'Suspend TARGET_VM or all VMs.' opts.separator '' opts.separator 'OPTIONS:' opts.on '--all', 'Suspend all running VMs' do @options.all = true end end optparse end def summary 'Suspend a VM' end end end end fission-0.5.0/lib/fission/command/snapshot_create.rb0000644000076400007640000000162612511713252021573 0ustar pravipravimodule Fission class Command class SnapshotCreate < Command def execute super incorrect_arguments unless @args.count == 2 vm = VM.new @args[0] snap_name = @args[1] output "Creating snapshot" response = vm.create_snapshot snap_name if response.successful? output "Snapshot '#{snap_name}' created" else output_and_exit "There was an error creating the snapshot. The error was:\n#{response.message}", response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission snapshot create TARGET_VM SNAPSHOT_NAME" opts.separator '' opts.separator 'Creates a snapshot of TARGET_VM named SNAPSHOT_NAME' end optparse end def summary 'Create a snapshot of a VM' end end end end fission-0.5.0/lib/fission/command/status.rb0000644000076400007640000000161712511713252017734 0ustar pravipravimodule Fission class Command class Status < Command def execute super response = VM.all_with_status unless response.successful? output_and_exit "There was an error getting the status of the VMs. The error was:\n#{response.message}", response.code end vms_status = response.data longest_vm_name = vms_status.keys.max { |a,b| a.length <=> b.length } vms_status.each_pair do |vm_name, status| output_printf "%-#{longest_vm_name.length}s [%s]\n", vm_name, status end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission status" opts.separator '' opts.separator 'Lists the status for all known VMs.' end optparse end def summary 'Show the status of all VMs' end end end end fission-0.5.0/lib/fission/command/snapshot_delete.rb0000644000076400007640000000162212511713252021566 0ustar pravipravimodule Fission class Command class SnapshotDelete < Command def execute super incorrect_arguments unless @args.count == 2 vm = VM.new @args[0] snap_name = @args[1] output "Deleting snapshot" response = vm.delete_snapshot snap_name if response.successful? output "Snapshot '#{snap_name}' deleted" else output_and_exit "There was an error deleting the snapshot. The error was:\n#{response.message}", response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission snapshot delete TARGET_VM SNAPSHOT_NAME" opts.separator '' opts.separator 'Deletes the snapshot SNAPSHOT_NAME of TARGET_VM' end optparse end def summary 'Delete a snapshot of a VM' end end end end fission-0.5.0/lib/fission/command/clone.rb0000644000076400007640000000304312511713252017504 0ustar pravipravimodule Fission class Command class Clone < Command def initialize(args=[]) super @options.start = false end def execute super incorrect_arguments unless @args.count > 1 source_vm = Fission::VM.new @args.first target_vm = Fission::VM.new @args[1] clone_response = VM.clone source_vm.name, target_vm.name if clone_response.successful? output '' output 'Clone complete!' if @options.start output "Starting '#{target_vm.name}'" start_response = target_vm.start if start_response.successful? output "VM '#{target_vm.name}' started" else output_and_exit "There was an error starting the VM. The error was:\n#{start_response.message}", start_response.code end end else output_and_exit "There was an error cloning the VM. The error was:\n#{clone_response.message}", clone_response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission clone SOURCE_VM TARGET_VM [OPTIONS]" opts.separator '' opts.separator 'Clones SOURCE_VM to a new VM (TARGET_VM).' opts.separator '' opts.separator 'OPTIONS:' opts.on '--start', 'Start the VM after cloning' do @options.start = true end end optparse end def summary 'Clone a VM' end end end end fission-0.5.0/lib/fission/command/info.rb0000644000076400007640000000330512511713252017340 0ustar pravipravimodule Fission class Command class Info < Command def execute super incorrect_arguments unless @args.count == 1 vm = VM.new @args.first output "name: #{vm.name}" guest_os_response = vm.guestos if guest_os_response.successful? os = guest_os_response.data.empty? ? 'unknown' : guest_os_response.data output "os: #{os}" else output_and_exit "There was an error getting the OS info. The error was:\n#{guest_os_response.message}", guest_os_response.code end hardware_response = vm.hardware_info if hardware_response.successful? hardware_response.data.each_pair do |k, v| output "#{k}: #{v}" end else output_and_exit "There was an error getting the hardware info. The error was:\n#{hardware_response.message}", hardware_response.code end network_response = vm.network_info if network_response.successful? network_response.data.each_pair do |int, data| data.each_pair do |k, v| output "#{int} #{k.gsub(/[-_]/, ' ')}: #{v}" end output "" end else output_and_exit "There was an error getting the network info. The error was:\n#{network_response.message}", network_response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = 'Usage: fission info TARGET_VM' opts.separator '' opts.separator 'Lists known information about TARGET_VM' end optparse end def summary 'Show information for a VM' end end end end fission-0.5.0/lib/fission/command/snapshot_revert.rb0000644000076400007640000000164712511713252021642 0ustar pravipravimodule Fission class Command class SnapshotRevert < Command def execute super incorrect_arguments unless @args.count == 2 vm = VM.new @args[0] snap_name = @args[1] output "Reverting to snapshot '#{snap_name}'" response = vm.revert_to_snapshot snap_name if response.successful? output "Reverted to snapshot '#{snap_name}'" else output_and_exit "There was an error reverting to the snapshot. The error was:\n#{response.message}", response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission snapshot revert TARGET_VM TARGET_SNAPSHOT" opts.separator '' opts.separator 'Reverts TARGET_VM to TARGET_SNAPSHOT' end optparse end def summary 'Revert a VM to a snapshot' end end end end fission-0.5.0/lib/fission/command/start.rb0000644000076400007640000000223212511713252017540 0ustar pravipravimodule Fission class Command class Start < Command def initialize(args=[]) super @options.headless = false end def execute super incorrect_arguments if @args.empty? vm = VM.new @args.first output "Starting '#{vm.name}'" start_args = {} start_args[:headless] = true if @options.headless response = vm.start start_args if response.successful? output "VM '#{vm.name}' started" else output_and_exit "There was a problem starting the VM. The error was:\n#{response.message}", response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission start TARGET_VM [OPTIONS]" opts.separator '' opts.separator 'Starts TARGET_VM.' opts.separator '' opts.separator 'OPTIONS:' opts.on '--headless', 'Start the VM in headless mode (i.e. no Fusion GUI console)' do @options.headless = true end end optparse end def summary 'Start a VM' end end end end fission-0.5.0/lib/fission/command/delete.rb0000644000076400007640000000411712511713252017651 0ustar pravipravimodule Fission class Command class Delete < Command def initialize(args=[]) super @options.force = false end def execute super incorrect_arguments if @args.count < 1 vm = VM.new @args.first running_response = vm.running? if running_response.successful? if running_response.data output 'VM is currently running' if @options.force output 'Going to stop it' Command::Stop.new([vm.name]).execute else output_and_exit "Either stop/suspend the VM or use '--force' and try again.", 1 end end else output_and_exit "There was an error determining if the VM is running. The error was:\n#{running_response.message}", running_response.code end if Fusion.running? output 'It looks like the Fusion GUI is currently running' if @options.force output 'The Fusion metadata for the VM may not be removed completely' else output "Either exit the Fusion GUI or use '--force' and try again" output_and_exit "NOTE: Forcing a VM deletion with the Fusion GUI running may not clean up all of the VM metadata", 1 end end delete_response = vm.delete if delete_response.successful? output '' output "Deletion complete!" else output_and_exit "There was an error deleting the VM. The error was:\n#{delete_response.message}", delete_response.code end end def option_parser optparse = OptionParser.new do |opts| opts.banner = "Usage: fission delete TARGET_VM [OPTIONS]" opts.separator '' opts.separator 'Deletes TARGET_VM.' opts.separator '' opts.separator 'OPTIONS:' opts.on '--force', "Stop the VM if it's running and then delete it" do @options.force = true end end optparse end def summary 'Delete a VM' end end end end fission-0.5.0/lib/fission/command.rb0000644000076400007640000000472212511713252016411 0ustar pravipravirequire 'forwardable' require 'fission/command_helpers' module Fission class Command include Fission::CommandHelpers extend Forwardable def_delegators :@ui, :output, :output_and_exit, :output_printf # Internal: Returns the OpenStruct options of the command. attr_reader :options # Internal: Returns the Array arguments of the command. attr_reader :args # Internal: Initializes a new Command with some basic setup. This is # intended to be used as a base class for other command classes to inherit # from. # # args - Array of arguments which will be assigned to the args instance # variable. # # Examples # # Fission::Command.new ['foo', 'bar'] def initialize(args=[]) ui @options = OpenStruct.new @args = args end # Internal: Primary method for performing an action within a command. # # Examples # # command.execute # # Returns nothing def execute parse_arguments end # Internal: Helper method used to delegate UI related methods through. # # Examples # # command.ui.output 'foo' # # Returns a UI instance. def ui @ui ||= UI.new end # Internal: Helper method to determine the command name of command class. # This should only be called against descendants of this class. # # #xamples: # Fission::Command::SnapshotList.new.command_name # # => 'snapshot list' # # Returns the command name as a String. def command_name(klass=self) klass.class.name.split('::')[2]. gsub(/([a-z\d])([A-Z])/,'\1_\2'). gsub('_', ' ').downcase end # Internal: Summmary of the command. This is to be implemented by any # class which inherits from this class. # # Examples # command.summary # # => 'This command does x and y' # # Returns a String summary of the command. def summary raise NotImplementedError end # Internal: Helper method to return the help text of a command. This is # intended to be used by a command class which inherits from this class. # This method will call the 'option_parser' method which must be defined in # any class which inherits from this class. # # Examples # # Fission::Command::Suspend.help # # Returns a String of the output parser text. def self.help self.new.option_parser.to_s end end end fission-0.5.0/lib/fission/core_ext/0000755000076400007640000000000012511713252016251 5ustar pravipravifission-0.5.0/lib/fission/core_ext/class.rb0000644000076400007640000000015312511713252017702 0ustar pravipraviclass Class def descendants ObjectSpace.each_object(Class).select { |klass| klass < self } end end fission-0.5.0/lib/fission/core_ext/object.rb0000644000076400007640000000421012511713252020041 0ustar pravipravi# this is from active_support # github.com/rails/rails/activesupport # class Object # An object is blank if it's false, empty, or a whitespace string. # For example, "", " ", +nil+, [], and {} are blank. # # This simplifies: # # if !address.nil? && !address.empty? # # ...to: # # if !address.blank? def blank? respond_to?(:empty?) ? empty? : !self end # An object is present if it's not blank?. def present? !blank? end # Returns object if it's present? otherwise returns +nil+. # object.presence is equivalent to object.present? ? object : nil. # # This is handy for any representation of objects where blank is the same # as not present at all. For example, this simplifies a common check for # HTTP POST/query parameters: # # state = params[:state] if params[:state].present? # country = params[:country] if params[:country].present? # region = state || country || 'US' # # ...becomes: # # region = params[:state].presence || params[:country].presence || 'US' def presence self if present? end end class NilClass # +nil+ is blank: # # nil.blank? # => true # def blank? true end end class FalseClass # +false+ is blank: # # false.blank? # => true # def blank? true end end class TrueClass # +true+ is not blank: # # true.blank? # => false # def blank? false end end class Array # An array is blank if it's empty: # # [].blank? # => true # [1,2,3].blank? # => false # alias_method :blank?, :empty? end class Hash # A hash is blank if it's empty: # # {}.blank? # => true # {:key => 'value'}.blank? # => false # alias_method :blank?, :empty? end class String # A string is blank if it's empty or contains whitespaces only: # # "".blank? # => true # " ".blank? # => true # " something here ".blank? # => false # def blank? self !~ /\S/ end end class Numeric #:nodoc: # No number is blank: # # 1.blank? # => false # 0.blank? # => false # def blank? false end end fission-0.5.0/lib/fission/core_ext/file.rb0000644000076400007640000000027512511713252017521 0ustar pravipraviclass File # from ptools def self.binary?(file) s = (File.read(file, File.stat(file).blksize) || "").split(//) ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30 end end fission-0.5.0/Rakefile0000644000076400007640000000030512511713252013664 0ustar pravipravirequire 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core/rake_task' task :default => [:spec] desc 'Run specs' RSpec::Core::RakeTask.new do |t| t.rspec_opts = %w(-fs --color) end fission-0.5.0/.gitignore0000644000076400007640000000004712511713252014212 0ustar pravipravi*.gem .bundle Gemfile.lock doc/* pkg/*