fission 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -2,5 +2,12 @@
2
2
 
3
3
  ## head
4
4
 
5
+ ## 0.2.0 (07/13/2011)
6
+ * add 'status' command
7
+ * add 'start' command
8
+ * add 'stop' command
9
+ * add 'suspend' command
10
+ * add support for cloning single and split disk VMs
11
+
5
12
  ## 0.1.0 (05/17/2011)
6
13
  Initial release
data/README.md CHANGED
@@ -1,19 +1,7 @@
1
1
  # Fission
2
2
 
3
3
  ## Intro
4
- Fission is a simple command line tool for cloning of VMware Fusion VMs.
5
-
6
-
7
- ## Config
8
- By default, fission will use the default VMware Fusion VM directory
9
- (~/Documents/Virtual Machines.localized/) when cloning. If you want to use a
10
- different directory, you can set this in a config file.
11
-
12
- The config file needs to be in yaml format and live at '~/.fissionrc'
13
-
14
- $cat ~/.fissionrc
15
- ---
16
- vm_dir: "/vm"
4
+ Fission is a simple command line tool for managing VMware Fusion VMs.
17
5
 
18
6
 
19
7
  ## Install
@@ -22,7 +10,29 @@ The config file needs to be in yaml format and live at '~/.fissionrc'
22
10
 
23
11
  ## Usage
24
12
  ### Clone
25
- fission clone existing_vm new_vm
13
+ fission clone existing_vm new_vm [--start]
14
+
15
+ If you provide '--start', then the new VM will be powered on after cloning
16
+
17
+ ### Start
18
+ fission start my_vm
19
+
20
+ Starts the VM
21
+
22
+ ### Status
23
+ fission status
24
+
25
+ Displays the status (running or not) of all of the VMs found
26
+
27
+ ### Stop
28
+ fission stop my_vm
29
+
30
+ Stops the VM
31
+
32
+ ### Suspend
33
+ fission suspend my_vm
34
+
35
+ Suspends the VM
26
36
 
27
37
  ### Help
28
38
  fission -h
@@ -32,7 +42,23 @@ or just
32
42
  fission
33
43
 
34
44
 
45
+ ## Config
46
+ By default, fission will use the default VMware Fusion VM directory
47
+ (~/Documents/Virtual Machines.localized/) when cloning. If you want to use a
48
+ different directory, you can set this in a config file.
49
+
50
+ The config file needs to be in yaml format and live at '~/.fissionrc'
51
+
52
+ $cat ~/.fissionrc
53
+ ---
54
+ vm_dir: "/vm"
55
+
56
+
35
57
  ## Other Notable Info
58
+ The name of the VM used in the previous examples should be the directory name
59
+ of the VM minus the '.vmwarevm' extension. Typically the VM name and the
60
+ directory name are the same.
61
+
36
62
  As of now, VMware Fusion doesn't provide an easy, out of
37
63
  the box, way to modify the personality (hostname, ip, etc.) of a VM. Because of
38
64
  this, a clone created by fission is an _exact_ copy of the original (including
@@ -40,8 +66,8 @@ hostname, ip address, etc.). Most likely, this isn't what you want.
40
66
 
41
67
  One approach is to create a VM which will act as a template. Create the VM with
42
68
  the desired install method (ideally with easy install) and settings, but do not
43
- power on the VM. You can create clones from this VM and when you power it on,
44
- it will start the OS install process (and assign a new ip, etc.)
69
+ power on the VM. You can then create clones from this VM 'template'. When you
70
+ power on the clone, it will start the OS install process (and assign a new ip, etc.).
45
71
 
46
72
 
47
73
  ## Contribute
@@ -49,3 +75,7 @@ it will start the OS install process (and assign a new ip, etc.)
49
75
  * Make your feature addition or bug fix (with tests) in a topic branch
50
76
  * Bonus points for not mucking with the gemspec or version
51
77
  * Send a pull request and I'll get it integrated
78
+
79
+
80
+ ## License
81
+ See LICENSE
data/lib/fission.rb CHANGED
@@ -8,8 +8,13 @@ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
8
8
  require 'fission/cli'
9
9
  require 'fission/command'
10
10
  require 'fission/command/clone'
11
+ require 'fission/command/start'
12
+ require 'fission/command/status'
13
+ require 'fission/command/stop'
14
+ require 'fission/command/suspend'
11
15
  require 'fission/config'
12
16
  require 'fission/core_ext/class'
17
+ require 'fission/core_ext/file'
13
18
  require 'fission/core_ext/object'
14
19
  require 'fission/ui'
15
20
  require 'fission/vm'
data/lib/fission/cli.rb CHANGED
@@ -28,15 +28,22 @@ module Fission
28
28
  exit(1)
29
29
  end
30
30
 
31
- case args.first
32
- when 'clone'
33
- @command = Fission::Command::Clone.new args.drop 1
34
- @command.execute
31
+ if commands.include?(args.first)
32
+ @cmd = Fission::Command.const_get(args.first.capitalize).new args.drop 1
33
+ @cmd.execute
35
34
  else
36
35
  show_all_help(optparse)
37
- exit(0)
36
+ exit(1)
37
+ end
38
+ end
39
+
40
+ def self.commands
41
+ cmds = []
42
+ Dir.entries(File.join(File.dirname(__FILE__), 'command')).select do |file|
43
+ cmds << File.basename(file, '.rb') unless File.directory? file
38
44
  end
39
45
 
46
+ cmds
40
47
  end
41
48
 
42
49
  private
@@ -0,0 +1,42 @@
1
+ module Fission
2
+ class Command
3
+ class Start < Command
4
+
5
+ def initialize(args=[])
6
+ super
7
+ end
8
+
9
+ def execute
10
+ unless args.count == 1
11
+ Fission.ui.output self.class.help
12
+ Fission.ui.output ""
13
+ Fission.ui.output_and_exit "Incorrect arguments for start command", 1
14
+ end
15
+
16
+ vm_name = args.first
17
+
18
+ unless Fission::VM.exists? vm_name
19
+ Fission.ui.output_and_exit "Unable to find the VM #{vm_name} (#{Fission::VM.path(vm_name)})", 1
20
+ end
21
+
22
+ if VM.all_running.include?(vm_name)
23
+ Fission.ui.output ''
24
+ Fission.ui.output_and_exit "VM '#{vm_name}' is already running", 0
25
+ end
26
+
27
+ Fission.ui.output "Starting '#{vm_name}'"
28
+ @vm = Fission::VM.new vm_name
29
+ @vm.start
30
+ end
31
+
32
+ def option_parser
33
+ optparse = OptionParser.new do |opts|
34
+ opts.banner = "\nstart usage: fission start vm"
35
+ end
36
+
37
+ optparse
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,31 @@
1
+ module Fission
2
+ class Command
3
+ class Status < Command
4
+
5
+ def initialize(args=[])
6
+ super
7
+ end
8
+
9
+ def execute
10
+ all_vms = VM.all
11
+ all_running_vms = VM.all_running
12
+
13
+ longest_vm_name = all_vms.max { |a,b| a.length <=> b.length }
14
+
15
+ VM.all.each do |vm|
16
+ status = all_running_vms.include?(vm) ? '[running]' : '[not running]'
17
+ Fission.ui.output_printf "%-#{longest_vm_name.length}s %s\n", vm, status
18
+ end
19
+ end
20
+
21
+ def option_parser
22
+ optparse = OptionParser.new do |opts|
23
+ opts.banner = "\nstatus usage: fission status"
24
+ end
25
+
26
+ optparse
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ module Fission
2
+ class Command
3
+ class Stop < Command
4
+
5
+ def initialize(args=[])
6
+ super
7
+ end
8
+
9
+ def execute
10
+ unless args.count == 1
11
+ Fission.ui.output self.class.help
12
+ Fission.ui.output ""
13
+ Fission.ui.output_and_exit "Incorrect arguments for stop command", 1
14
+ end
15
+
16
+ vm_name = args.first
17
+
18
+ unless Fission::VM.exists? vm_name
19
+ Fission.ui.output_and_exit "Unable to find the VM #{vm_name} (#{Fission::VM.path(vm_name)})", 1
20
+ end
21
+
22
+ unless VM.all_running.include?(vm_name)
23
+ Fission.ui.output ''
24
+ Fission.ui.output_and_exit "VM '#{vm_name}' is not running", 0
25
+ end
26
+
27
+ Fission.ui.output "Stopping '#{vm_name}'"
28
+ @vm = Fission::VM.new vm_name
29
+ @vm.stop
30
+ end
31
+
32
+ def option_parser
33
+ optparse = OptionParser.new do |opts|
34
+ opts.banner = "\nstop usage: fission stop vm"
35
+ end
36
+
37
+ optparse
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ module Fission
2
+ class Command
3
+ class Suspend < Command
4
+
5
+ def initialize(args=[])
6
+ super
7
+ end
8
+
9
+ def execute
10
+ unless args.count == 1
11
+ Fission.ui.output self.class.help
12
+ Fission.ui.output ""
13
+ Fission.ui.output_and_exit "Incorrect arguments for suspend command", 1
14
+ end
15
+
16
+ vm_name = args.first
17
+
18
+ unless Fission::VM.exists? vm_name
19
+ Fission.ui.output_and_exit "Unable to find the VM #{vm_name} (#{Fission::VM.path(vm_name)})", 1
20
+ end
21
+
22
+ unless VM.all_running.include?(vm_name)
23
+ Fission.ui.output ''
24
+ Fission.ui.output_and_exit "VM '#{vm_name}' is not running", 0
25
+ end
26
+
27
+ Fission.ui.output "suspending '#{vm_name}'"
28
+ @vm = Fission::VM.new vm_name
29
+ @vm.suspend
30
+ end
31
+
32
+ def option_parser
33
+ optparse = OptionParser.new do |opts|
34
+ opts.banner = "\nsuspend usage: fission suspend vm"
35
+ end
36
+
37
+ optparse
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -13,6 +13,7 @@ module Fission
13
13
  end
14
14
 
15
15
  @attributes['vmrun_bin'] = '/Library/Application Support/VMware Fusion/vmrun'
16
+ @attributes['vmrun_cmd'] = "#{@attributes['vmrun_bin'].gsub(' ', '\ ')} -T fusion"
16
17
  end
17
18
 
18
19
  private
@@ -0,0 +1,7 @@
1
+ class File
2
+ # from ptools
3
+ def self.binary?(file)
4
+ s = (File.read(file, File.stat(file).blksize) || "").split(//)
5
+ ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30
6
+ end
7
+ end
data/lib/fission/ui.rb CHANGED
@@ -10,6 +10,10 @@ module Fission
10
10
  @stdout.puts s
11
11
  end
12
12
 
13
+ def output_printf(string, key, value)
14
+ @stdout.send :printf, string, key, value
15
+ end
16
+
13
17
  def output_and_exit(s, exit_code)
14
18
  output s
15
19
  exit exit_code
@@ -1,3 +1,3 @@
1
1
  module Fission
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/fission/vm.rb CHANGED
@@ -7,7 +7,7 @@ module Fission
7
7
  end
8
8
 
9
9
  def start
10
- command = "#{Fission.config.attributes['vmrun_bin'].gsub(' ', '\ ' )} -T fusion start #{conf_file.gsub ' ', '\ '} gui 2>&1"
10
+ command = "#{Fission.config.attributes['vmrun_cmd']} start #{conf_file.gsub ' ', '\ '} gui 2>&1"
11
11
  output = `#{command}`
12
12
 
13
13
  if $?.exitstatus == 0
@@ -17,10 +17,62 @@ module Fission
17
17
  end
18
18
  end
19
19
 
20
+ def stop
21
+ command = "#{Fission.config.attributes['vmrun_cmd']} stop #{conf_file.gsub ' ', '\ '} 2>&1"
22
+ output = `#{command}`
23
+
24
+ if $?.exitstatus == 0
25
+ Fission.ui.output "VM stopped"
26
+ else
27
+ Fission.ui.output "There was a problem stopping the VM. The error was:\n#{output}"
28
+ end
29
+ end
30
+
31
+ def suspend
32
+ command = "#{Fission.config.attributes['vmrun_cmd']} suspend #{conf_file.gsub ' ', '\ '} 2>&1"
33
+ output = `#{command}`
34
+
35
+ if $?.exitstatus == 0
36
+ Fission.ui.output "VM suspended"
37
+ else
38
+ Fission.ui.output "There was a problem suspending the VM. The error was:\n#{output}"
39
+ end
40
+ end
41
+
20
42
  def conf_file
21
43
  File.join self.class.path(@name), "#{@name}.vmx"
22
44
  end
23
45
 
46
+ def self.all
47
+ vm_dirs = Dir[File.join Fission.config.attributes['vm_dir'], '*.vmwarevm'].select do |d|
48
+ File.directory? d
49
+ end
50
+
51
+ vm_dirs.map { |d| File.basename d, '.vmwarevm' }
52
+ end
53
+
54
+ def self.all_running
55
+ command = "#{Fission.config.attributes['vmrun_cmd']} list"
56
+
57
+ output = `#{command}`
58
+
59
+ vms = []
60
+
61
+ if $?.exitstatus == 0
62
+ output.split("\n").each do |vm|
63
+ if vm.include?('.vmx')
64
+ if File.exists?(vm) && (File.extname(vm) == '.vmx')
65
+ vms << File.basename(vm, '.vmx')
66
+ end
67
+ end
68
+ end
69
+ else
70
+ Fission.ui.output_and_exit "Unable to determine the list of running VMs", 1
71
+ end
72
+
73
+ vms
74
+ end
75
+
24
76
  def self.exists?(vm_name)
25
77
  File.directory? path(vm_name)
26
78
  end
@@ -50,11 +102,13 @@ module Fission
50
102
  end
51
103
 
52
104
  def self.update_config(from, to)
53
- ['.vmdk', '.vmx', '.vmxf'].each do |ext|
105
+ ['.vmx', '.vmxf', '.vmdk'].each do |ext|
54
106
  file = File.join path(to), "#{to}#{ext}"
55
- text = File.read file
56
- text.gsub! from, to
57
- File.open(file, 'w'){ |f| f.print text }
107
+
108
+ unless File.binary?(file)
109
+ text = (File.read file).gsub from, to
110
+ File.open(file, 'w'){ |f| f.print text }
111
+ end
58
112
  end
59
113
  end
60
114
 
@@ -6,6 +6,12 @@ describe Fission::CLI do
6
6
  Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
7
7
  end
8
8
 
9
+ describe 'self.commands' do
10
+ it 'should return the list of commands' do
11
+ Fission::CLI.commands.should == ['clone', 'start', 'status', 'stop', 'suspend']
12
+ end
13
+ end
14
+
9
15
  describe 'execute' do
10
16
 
11
17
  describe 'with no arguments' do
@@ -45,17 +51,50 @@ describe Fission::CLI do
45
51
 
46
52
  end
47
53
 
48
- describe 'clone' do
54
+ describe 'with the sub command' do
49
55
  before :each do
50
- @clone_mock = mock('clone_mock')
51
- Fission::Command::Clone.stub!(:help).and_return('')
56
+ @cmd_mock = mock('cmd')
57
+ @cmd_mock.should_receive(:execute)
58
+ end
59
+
60
+ describe 'clone' do
61
+ it "should try to clone the vm" do
62
+ Fission::Command::Clone.stub!(:help).and_return('')
63
+ Fission::Command::Clone.should_receive(:new).with(['foo', 'bar']).and_return(@cmd_mock)
64
+ Fission::CLI.execute ['clone', 'foo', 'bar']
65
+ end
52
66
  end
53
67
 
54
- it "should try to clone the vm" do
55
- @clone_mock.should_receive(:execute)
56
- Fission::Command::Clone.should_receive(:new).with(['foo', 'bar']).and_return(@clone_mock)
68
+ describe 'start' do
69
+ it "should try to start the vm" do
70
+ Fission::Command::Start.stub!(:help).and_return('')
71
+ Fission::Command::Start.should_receive(:new).with(['foo']).and_return(@cmd_mock)
72
+ Fission::CLI.execute ['start', 'foo']
73
+ end
74
+ end
57
75
 
58
- Fission::CLI.execute ['clone', 'foo', 'bar']
76
+ describe 'status' do
77
+ it "should try to get the status for all VMs" do
78
+ Fission::Command::Status.stub!(:help).and_return('')
79
+ Fission::Command::Status.should_receive(:new).and_return(@cmd_mock)
80
+ Fission::CLI.execute ['status']
81
+ end
82
+ end
83
+
84
+ describe 'stop' do
85
+ it "should try to stop the vm" do
86
+ Fission::Command::Stop.stub!(:help).and_return('')
87
+ Fission::Command::Stop.should_receive(:new).with(['foo']).and_return(@cmd_mock)
88
+ Fission::CLI.execute ['stop', 'foo']
89
+ end
90
+ end
91
+
92
+ describe 'suspend' do
93
+ it "should try to suspend the vm" do
94
+ Fission::Command::Suspend.stub!(:help).and_return('')
95
+ Fission::Command::Suspend.should_receive(:new).with(['foo']).and_return(@cmd_mock)
96
+ Fission::CLI.execute ['suspend', 'foo']
97
+ end
59
98
  end
60
99
  end
61
100
 
@@ -0,0 +1,71 @@
1
+ require File.expand_path('../../../spec_helper.rb', __FILE__)
2
+
3
+ describe Fission::Command::Start do
4
+ before :all do
5
+ @vm_info = ['foo']
6
+ end
7
+
8
+ before :each do
9
+ @string_io = StringIO.new
10
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
11
+ end
12
+
13
+ describe 'execute' do
14
+ it "should output an error and the help when no VM argument is passed in" do
15
+ Fission::Command::Start.should_receive(:help)
16
+
17
+ lambda {
18
+ command = Fission::Command::Start.new
19
+ command.execute
20
+ }.should raise_error SystemExit
21
+
22
+ @string_io.string.should match /Incorrect arguments for start command/
23
+ end
24
+
25
+ it "should output an error and exit if it can't find the vm" do
26
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(false)
27
+
28
+ lambda {
29
+ command = Fission::Command::Start.new @vm_info
30
+ command.execute
31
+ }.should raise_error SystemExit
32
+
33
+ @string_io.string.should match /Unable to find the VM #{@vm_info.first}/
34
+ end
35
+
36
+
37
+ it "should output and exit if the vm is already running" do
38
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
39
+ Fission::VM.should_receive(:all_running).and_return(@vm_info)
40
+
41
+ lambda {
42
+ command = Fission::Command::Start.new @vm_info
43
+ command.execute
44
+ }.should raise_error SystemExit
45
+
46
+ @string_io.string.should match /VM '#{@vm_info.first}' is already running/
47
+ end
48
+
49
+ it 'should try to start the vm if it is not running' do
50
+ @vm_mock = mock('vm_mock')
51
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
52
+ Fission::VM.should_receive(:all_running).and_return([])
53
+ Fission::VM.should_receive(:new).with(@vm_info.first).and_return(@vm_mock)
54
+ @vm_mock.should_receive(:start)
55
+
56
+ command = Fission::Command::Start.new @vm_info
57
+ command.execute
58
+
59
+ @string_io.string.should match /Starting '#{@vm_info.first}'/
60
+ end
61
+
62
+ end
63
+
64
+ describe 'help' do
65
+ it 'should output info for this command' do
66
+ output = Fission::Command::Start.help
67
+
68
+ output.should match /start vm/
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,38 @@
1
+ require File.expand_path('../../../spec_helper.rb', __FILE__)
2
+
3
+ describe Fission::Command::Status do
4
+ before :each do
5
+ @string_io = StringIO.new
6
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
7
+ end
8
+
9
+ describe 'execute' do
10
+ before :each do
11
+ Fission::VM.stub!(:all).and_return(['foo', 'bar', 'baz'])
12
+ Fission::VM.stub!(:all_running).and_return(['foo', 'baz'])
13
+ end
14
+
15
+ it 'should output the VMs which are running' do
16
+ command = Fission::Command::Status.new
17
+ command.execute
18
+
19
+ @string_io.string.should match /foo.+[running]/
20
+ @string_io.string.should match /baz.+[running]/
21
+ end
22
+
23
+ it 'should output the VMs which are not running' do
24
+ command = Fission::Command::Status.new
25
+ command.execute
26
+
27
+ @string_io.string.should match /bar.+[not running]/
28
+ end
29
+ end
30
+
31
+ describe 'help' do
32
+ it 'should output info for this command' do
33
+ output = Fission::Command::Status.help
34
+
35
+ output.should match /status/
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path('../../../spec_helper.rb', __FILE__)
2
+
3
+ describe Fission::Command::Stop do
4
+ before :all do
5
+ @vm_info = ['foo']
6
+ end
7
+
8
+ before :each do
9
+ @string_io = StringIO.new
10
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
11
+ end
12
+
13
+ describe 'execute' do
14
+ it "should output an error and the help when no VM argument is passed in" do
15
+ Fission::Command::Stop.should_receive(:help)
16
+
17
+ lambda {
18
+ command = Fission::Command::Stop.new
19
+ command.execute
20
+ }.should raise_error SystemExit
21
+
22
+ @string_io.string.should match /Incorrect arguments for stop command/
23
+ end
24
+
25
+ it "should output an error and exit if it can't find the vm" do
26
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(false)
27
+
28
+ lambda {
29
+ command = Fission::Command::Stop.new @vm_info
30
+ command.execute
31
+ }.should raise_error SystemExit
32
+
33
+ @string_io.string.should match /Unable to find the VM #{@vm_info.first}/
34
+ end
35
+
36
+
37
+ it "should output and exit if the vm is not running" do
38
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
39
+ Fission::VM.should_receive(:all_running).and_return([])
40
+
41
+ lambda {
42
+ command = Fission::Command::Stop.new @vm_info
43
+ command.execute
44
+ }.should raise_error SystemExit
45
+
46
+ @string_io.string.should match /VM '#{@vm_info.first}' is not running/
47
+ end
48
+
49
+ it 'should try to stop the vm if it is not running' do
50
+ @vm_mock = mock('vm_mock')
51
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
52
+ Fission::VM.should_receive(:all_running).and_return(@vm_info)
53
+ Fission::VM.should_receive(:new).with(@vm_info.first).and_return(@vm_mock)
54
+ @vm_mock.should_receive(:stop)
55
+
56
+ command = Fission::Command::Stop.new @vm_info
57
+ command.execute
58
+
59
+ @string_io.string.should match /Stopping '#{@vm_info.first}'/
60
+ end
61
+
62
+ end
63
+
64
+ describe 'help' do
65
+ it 'should output info for this command' do
66
+ output = Fission::Command::Stop.help
67
+
68
+ output.should match /stop vm/
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path('../../../spec_helper.rb', __FILE__)
2
+
3
+ describe Fission::Command::Suspend do
4
+ before :all do
5
+ @vm_info = ['foo']
6
+ end
7
+
8
+ before :each do
9
+ @string_io = StringIO.new
10
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
11
+ end
12
+
13
+ describe 'execute' do
14
+ it "should output an error and the help when no VM argument is passed in" do
15
+ Fission::Command::Suspend.should_receive(:help)
16
+
17
+ lambda {
18
+ command = Fission::Command::Suspend.new
19
+ command.execute
20
+ }.should raise_error SystemExit
21
+
22
+ @string_io.string.should match /Incorrect arguments for suspend command/
23
+ end
24
+
25
+ it "should output an error and exit if it can't find the vm" do
26
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(false)
27
+
28
+ lambda {
29
+ command = Fission::Command::Suspend.new @vm_info
30
+ command.execute
31
+ }.should raise_error SystemExit
32
+
33
+ @string_io.string.should match /Unable to find the VM #{@vm_info.first}/
34
+ end
35
+
36
+
37
+ it "should output and exit if the vm is not running" do
38
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
39
+ Fission::VM.should_receive(:all_running).and_return([])
40
+
41
+ lambda {
42
+ command = Fission::Command::Suspend.new @vm_info
43
+ command.execute
44
+ }.should raise_error SystemExit
45
+
46
+ @string_io.string.should match /VM '#{@vm_info.first}' is not running/
47
+ end
48
+
49
+ it 'should try to suspend the vm if it is running' do
50
+ @vm_mock = mock('vm_mock')
51
+ Fission::VM.should_receive(:exists?).with(@vm_info.first).and_return(true)
52
+ Fission::VM.should_receive(:all_running).and_return([@vm_info.first])
53
+ Fission::VM.should_receive(:new).with(@vm_info.first).and_return(@vm_mock)
54
+ @vm_mock.should_receive(:suspend)
55
+
56
+ command = Fission::Command::Suspend.new @vm_info
57
+ command.execute
58
+
59
+ @string_io.string.should match /suspending '#{@vm_info.first}'/
60
+ end
61
+
62
+ end
63
+
64
+ describe 'help' do
65
+ it 'should output info for this command' do
66
+ output = Fission::Command::Suspend.help
67
+
68
+ output.should match /suspend vm/
69
+ end
70
+ end
71
+ end
@@ -25,6 +25,13 @@ describe Fission::Config do
25
25
  end
26
26
  end
27
27
 
28
+ it 'should set vmrun_cmd' do
29
+ FakeFS do
30
+ @config = Fission::Config.new
31
+ @config.attributes['vmrun_cmd'].should == '/Library/Application\ Support/VMware\ Fusion/vmrun -T fusion'
32
+ end
33
+ end
34
+
28
35
  end
29
36
 
30
37
  end
@@ -11,6 +11,14 @@ describe Fission::UI do
11
11
  end
12
12
  end
13
13
 
14
+ describe 'output_printf' do
15
+ it 'should pass the arguments to printf' do
16
+ @output = mock('output')
17
+ @output.should_receive(:printf).with('foo', 'bar', 'baz')
18
+ Fission::UI.new(@output).output_printf('foo', 'bar', 'baz')
19
+ end
20
+ end
21
+
14
22
  describe 'output_and_exit' do
15
23
  it 'should show the desired text and exit with the desired exit code' do
16
24
  Fission::UI.any_instance.should_receive(:exit).and_return(1)
@@ -13,9 +13,12 @@ describe Fission::VM do
13
13
 
14
14
  describe 'start' do
15
15
  it 'should output that it was successful' do
16
+ $?.should_receive(:exitstatus).and_return(0)
16
17
  Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
17
18
  @vm = Fission::VM.new('foo')
18
- @vm.should_receive(:`).with("#{Fission.config.attributes['vmrun_bin'].gsub ' ', '\ '} -T fusion start #{(File.join(Fission::VM.path('foo'), 'foo.vmx')).gsub ' ', '\ '} gui 2>&1").and_return("it's all good")
19
+ @vm.should_receive(:`).
20
+ with("#{Fission.config.attributes['vmrun_cmd']} start #{@vm.conf_file.gsub(' ', '\ ')} gui 2>&1").
21
+ and_return("it's all good")
19
22
  @vm.start
20
23
 
21
24
  @string_io.string.should match /VM started/
@@ -25,19 +28,126 @@ describe Fission::VM do
25
28
  $?.should_receive(:exitstatus).and_return(1)
26
29
  Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
27
30
  @vm = Fission::VM.new('foo')
28
- @vm.should_receive(:`).with("#{Fission.config.attributes['vmrun_bin'].gsub ' ', '\ '} -T fusion start #{(File.join(Fission::VM.path('foo'), 'foo.vmx')).gsub ' ', '\ '} gui 2>&1").and_return("it blew up")
31
+ @vm.should_receive(:`).
32
+ with("#{Fission.config.attributes['vmrun_cmd']} start #{@vm.conf_file.gsub(' ', '\ ')} gui 2>&1").
33
+ and_return("it blew up")
29
34
  @vm.start
30
35
 
31
36
  @string_io.string.should match /There was a problem starting the VM.+it blew up.+/m
32
37
  end
33
38
  end
34
39
 
40
+ describe 'stop' do
41
+ it 'should output that it was successful' do
42
+ $?.should_receive(:exitstatus).and_return(0)
43
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
44
+ @vm = Fission::VM.new('foo')
45
+ @vm.should_receive(:`).
46
+ with("#{Fission.config.attributes['vmrun_cmd']} stop #{@vm.conf_file.gsub ' ', '\ '} 2>&1").
47
+ and_return("it's all good")
48
+ @vm.stop
49
+
50
+ @string_io.string.should match /VM stopped/
51
+ end
52
+
53
+ it 'it should output that it was unsuccessful' do
54
+ $?.should_receive(:exitstatus).and_return(1)
55
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
56
+ @vm = Fission::VM.new('foo')
57
+ @vm.should_receive(:`).
58
+ with("#{Fission.config.attributes['vmrun_cmd']} stop #{@vm.conf_file.gsub ' ', '\ '} 2>&1").
59
+ and_return("it blew up")
60
+ @vm.stop
61
+
62
+ @string_io.string.should match /There was a problem stopping the VM.+it blew up.+/m
63
+ end
64
+ end
65
+
66
+ describe 'suspend' do
67
+ it 'should output that it was successful' do
68
+ $?.should_receive(:exitstatus).and_return(0)
69
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
70
+ @vm = Fission::VM.new('foo')
71
+ @vm.should_receive(:`).
72
+ with("#{Fission.config.attributes['vmrun_cmd']} suspend #{@vm.conf_file.gsub ' ', '\ '} 2>&1").
73
+ and_return("it's all good")
74
+ @vm.suspend
75
+
76
+ @string_io.string.should match /VM suspended/
77
+ end
78
+
79
+ it 'it should output that it was unsuccessful' do
80
+ $?.should_receive(:exitstatus).and_return(1)
81
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
82
+ @vm = Fission::VM.new('foo')
83
+ @vm.should_receive(:`).
84
+ with("#{Fission.config.attributes['vmrun_cmd']} suspend #{@vm.conf_file.gsub ' ', '\ '} 2>&1").
85
+ and_return("it blew up")
86
+ @vm.suspend
87
+
88
+ @string_io.string.should match /There was a problem suspending the VM.+it blew up.+/m
89
+ end
90
+ end
91
+
35
92
  describe 'conf_file' do
36
93
  it 'should return the path to the conf file' do
37
94
  Fission::VM.new('foo').conf_file.should == File.join(Fission.config.attributes['vm_dir'], 'foo.vmwarevm', 'foo.vmx')
38
95
  end
39
96
  end
40
97
 
98
+ describe "self.all" do
99
+ it "should return the list of VMs" do
100
+ vm_root = Fission.config.attributes['vm_dir']
101
+ Dir.should_receive(:[]).and_return(["#{File.join vm_root, 'foo.vmwarevm' }", "#{File.join vm_root, 'bar.vmwarevm' }"])
102
+
103
+ vm_root = Fission.config.attributes['vm_dir']
104
+ File.should_receive(:directory?).with("#{File.join vm_root, 'foo.vmwarevm'}").and_return(true)
105
+ File.should_receive(:directory?).with("#{File.join vm_root, 'bar.vmwarevm'}").and_return(true)
106
+ Fission::VM.all.should == ['foo', 'bar']
107
+ end
108
+
109
+ it "should not return an item in the list if it isn't a directory" do
110
+ vm_root = Fission.config.attributes['vm_dir']
111
+ Dir.should_receive(:[]).and_return((['foo', 'bar', 'baz'].map { |i| File.join vm_root, "#{i}.vmwarevm"}))
112
+ File.should_receive(:directory?).with("#{File.join vm_root, 'foo.vmwarevm'}").and_return(true)
113
+ File.should_receive(:directory?).with("#{File.join vm_root, 'bar.vmwarevm'}").and_return(true)
114
+ File.should_receive(:directory?).with("#{File.join vm_root, 'baz.vmwarevm'}").and_return(false)
115
+ Fission::VM.all.should == ['foo', 'bar']
116
+ end
117
+
118
+ it "should only query for items with an extension of .vmwarevm" do
119
+ dir_arg = File.join Fission.config.attributes['vm_dir'], '*.vmwarevm'
120
+ Dir.should_receive(:[]).with(dir_arg).and_return(['foo.vmwarevm', 'bar.vmwarevm'])
121
+ Fission::VM.all
122
+ end
123
+ end
124
+
125
+ describe 'self.all_running' do
126
+ it 'should list the running vms' do
127
+ list_output = "Total running VMs: 2\n/vm/foo.vmwarevm/foo.vmx\n/vm/bar.vmwarevm/bar.vmx\n/vm/baz.vmwarevm/baz.vmx\n"
128
+
129
+ $?.should_receive(:exitstatus).and_return(0)
130
+ Fission::VM.should_receive(:`).with("#{Fission.config.attributes['vmrun_cmd']} list").and_return(list_output)
131
+ [ 'foo', 'bar', 'baz'].each do |vm|
132
+ File.should_receive(:exists?).with("/vm/#{vm}.vmwarevm/#{vm}.vmx").and_return(true)
133
+ end
134
+
135
+ Fission::VM.all_running.should == ['foo', 'bar', 'baz']
136
+ end
137
+
138
+ it 'should output an error and exit if unable to get the list of running vms' do
139
+ $?.should_receive(:exitstatus).and_return(1)
140
+ Fission::VM.should_receive(:`).with("#{Fission.config.attributes['vmrun_cmd']} list").and_return("it blew up")
141
+ Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
142
+
143
+ lambda {
144
+ Fission::VM.all_running
145
+ }.should raise_error SystemExit
146
+
147
+ @string_io.string.should match /Unable to determine the list of running VMs/
148
+ end
149
+ end
150
+
41
151
  describe "self.path" do
42
152
  it "should return the path of the vm" do
43
153
  vm_path = File.join(Fission.config.attributes['vm_dir'], 'foo.vmwarevm').gsub '\\', ''
@@ -61,45 +171,75 @@ describe Fission::VM do
61
171
  end
62
172
  end
63
173
 
64
-
65
174
  describe "self.clone" do
66
175
  before :each do
67
176
  Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
68
- end
177
+ @source_vm = 'foo'
178
+ @target_vm = 'bar'
179
+ @vm_files = ['.vmx', '.vmxf', '.vmdk', '-s001.vmdk', '-s002.vmdk', '.vmsd']
69
180
 
70
- it 'should clone the vm to the target' do
71
- source_vm = 'foo'
72
- target_vm = 'bar'
73
- vm_files = [ '.vmx',
74
- '.vmxf',
75
- '.vmdk',
76
- '-s001.vmdk',
77
- '-s002.vmdk',
78
- '.vmsd' ]
181
+ FakeFS.activate!
79
182
 
80
- FakeFS do
81
- FileUtils.mkdir_p Fission::VM.path('foo')
183
+ FileUtils.mkdir_p Fission::VM.path('foo')
184
+
185
+ @vm_files.each do |file|
186
+ FileUtils.touch File.join(Fission::VM.path('foo'), "#{@source_vm}#{file}")
187
+ end
82
188
 
83
- vm_files.each do |file|
84
- FileUtils.touch File.join(Fission::VM.path('foo'), "#{source_vm}#{file}")
85
- end
189
+ ['.vmx', '.vmxf', '.vmdk'].each do |ext|
190
+ File.open(File.join(Fission::VM.path('foo'), "foo#{ext}"), 'w') { |f| f.write 'foo.vmdk'}
191
+ end
86
192
 
87
- File.open(File.join(Fission::VM.path('foo'), 'foo.vmx'), 'w') { |f| f.write 'foo.vmdk'}
193
+ ['.vmx', '.vmxf'].each do |ext|
194
+ File.should_receive(:binary?).with(File.join(Fission::VM.path('bar'), "bar#{ext}")).and_return(false)
195
+ end
196
+ end
88
197
 
89
- Fission::VM.clone source_vm, target_vm
198
+ after :each do
199
+ FakeFS.deactivate!
200
+ end
90
201
 
91
- File.directory?(Fission::VM.path('bar')).should == true
202
+ it 'should copy the vm files to the target' do
203
+ File.should_receive(:binary?).with(File.join(Fission::VM.path('bar'), "bar.vmdk")).and_return(true)
204
+ Fission::VM.clone @source_vm, @target_vm
205
+
206
+ File.directory?(Fission::VM.path('bar')).should == true
207
+
208
+ @vm_files.each do |file|
209
+ File.file?(File.join(Fission::VM.path('bar'), "#{@target_vm}#{file}")).should == true
210
+ end
211
+ end
92
212
 
93
- vm_files.each do |file|
94
- File.file?(File.join(Fission::VM.path('bar'), "#{target_vm}#{file}")).should == true
95
- end
213
+ it 'should update the target vm config files' do
214
+ File.should_receive(:binary?).with(File.join(Fission::VM.path('bar'), "bar.vmdk")).and_return(true)
215
+ Fission::VM.clone @source_vm, @target_vm
96
216
 
97
- conf_file = File.read File.join(Fission::VM.path('bar'), 'bar.vmx')
98
- conf_file.should == 'bar.vmdk'
217
+ ['.vmx', '.vmxf'].each do |ext|
218
+ File.read(File.join(Fission::VM.path('bar'), "bar#{ext}")).should_not match /foo/
219
+ File.read(File.join(Fission::VM.path('bar'), "bar#{ext}")).should match /bar/
99
220
  end
221
+ end
222
+
223
+ it "should not try to update the vmdk file if it's not a sparse disk" do
224
+ File.should_receive(:binary?).with(File.join(Fission::VM.path('bar'), "bar.vmdk")).and_return(true)
225
+ Fission::VM.clone @source_vm, @target_vm
226
+
227
+ File.read(File.join(Fission::VM.path('bar'), 'bar.vmdk')).should match /foo/
228
+ end
229
+
230
+ it "should update the vmdk when a sparse disk is found" do
231
+ File.should_receive(:binary?).with(File.join(Fission::VM.path('bar'), "bar.vmdk")).and_return(false)
232
+ Fission::VM.clone @source_vm, @target_vm
233
+
234
+ File.read(File.join(Fission::VM.path('bar'), 'bar.vmdk')).should match /bar/
235
+ end
236
+
237
+ it 'should output that the clone was successful' do
238
+ File.should_receive(:binary?).with(File.join(Fission::VM.path('bar'), "bar.vmdk")).and_return(true)
239
+ Fission::VM.clone @source_vm, @target_vm
100
240
 
101
- @string_io.string.should match /Cloning #{source_vm} to #{target_vm}/
102
- @string_io.string.should match /Configuring #{target_vm}/
241
+ @string_io.string.should match /Cloning #{@source_vm} to #{@target_vm}/
242
+ @string_io.string.should match /Configuring #{@target_vm}/
103
243
  end
104
244
 
105
245
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: fission
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tommy Bishop
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-18 00:00:00 Z
13
+ date: 2011-07-14 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -58,14 +58,23 @@ files:
58
58
  - lib/fission/cli.rb
59
59
  - lib/fission/command.rb
60
60
  - lib/fission/command/clone.rb
61
+ - lib/fission/command/start.rb
62
+ - lib/fission/command/status.rb
63
+ - lib/fission/command/stop.rb
64
+ - lib/fission/command/suspend.rb
61
65
  - lib/fission/config.rb
62
66
  - lib/fission/core_ext/class.rb
67
+ - lib/fission/core_ext/file.rb
63
68
  - lib/fission/core_ext/object.rb
64
69
  - lib/fission/ui.rb
65
70
  - lib/fission/version.rb
66
71
  - lib/fission/vm.rb
67
72
  - spec/fission/cli_spec.rb
68
73
  - spec/fission/command/clone_spec.rb
74
+ - spec/fission/command/start_spec.rb
75
+ - spec/fission/command/status_spec.rb
76
+ - spec/fission/command/stop_spec.rb
77
+ - spec/fission/command/suspend_spec.rb
69
78
  - spec/fission/command_spec.rb
70
79
  - spec/fission/config_spec.rb
71
80
  - spec/fission/ui_spec.rb
@@ -95,13 +104,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
104
  requirements: []
96
105
 
97
106
  rubyforge_project: fission
98
- rubygems_version: 1.8.2
107
+ rubygems_version: 1.8.5
99
108
  signing_key:
100
109
  specification_version: 3
101
110
  summary: Tool to clone VMware fusion VMs
102
111
  test_files:
103
112
  - spec/fission/cli_spec.rb
104
113
  - spec/fission/command/clone_spec.rb
114
+ - spec/fission/command/start_spec.rb
115
+ - spec/fission/command/status_spec.rb
116
+ - spec/fission/command/stop_spec.rb
117
+ - spec/fission/command/suspend_spec.rb
105
118
  - spec/fission/command_spec.rb
106
119
  - spec/fission/config_spec.rb
107
120
  - spec/fission/ui_spec.rb