fission 0.2.0 → 0.3.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -0
- data/README.md +44 -3
- data/fission.gemspec +3 -2
- data/lib/fission.rb +6 -0
- data/lib/fission/cli.rb +12 -6
- data/lib/fission/command/clone.rb +3 -4
- data/lib/fission/command/delete.rb +65 -0
- data/lib/fission/command/snapshot_create.rb +47 -0
- data/lib/fission/command/snapshot_list.rb +42 -0
- data/lib/fission/command/snapshot_revert.rb +47 -0
- data/lib/fission/command/start.rb +22 -4
- data/lib/fission/command/stop.rb +2 -2
- data/lib/fission/command/suspend.rb +29 -13
- data/lib/fission/config.rb +2 -0
- data/lib/fission/fusion.rb +13 -0
- data/lib/fission/metadata.rb +39 -0
- data/lib/fission/version.rb +1 -1
- data/lib/fission/vm.rb +100 -15
- data/spec/fission/cli_spec.rb +91 -11
- data/spec/fission/command/clone_spec.rb +2 -6
- data/spec/fission/command/delete_spec.rb +109 -0
- data/spec/fission/command/snapshot_create_spec.rb +88 -0
- data/spec/fission/command/snapshot_list_spec.rb +61 -0
- data/spec/fission/command/snapshot_revert_spec.rb +90 -0
- data/spec/fission/command/start_spec.rb +35 -6
- data/spec/fission/command/status_spec.rb +2 -2
- data/spec/fission/command/stop_spec.rb +1 -4
- data/spec/fission/command/suspend_spec.rb +27 -6
- data/spec/fission/command_spec.rb +0 -1
- data/spec/fission/config_spec.rb +10 -0
- data/spec/fission/fusion_spec.rb +22 -0
- data/spec/fission/metadata_spec.rb +100 -0
- data/spec/fission/ui_spec.rb +8 -12
- data/spec/fission/vm_spec.rb +268 -44
- data/spec/spec_helper.rb +0 -17
- metadata +40 -11
data/lib/fission/command/stop.rb
CHANGED
@@ -7,13 +7,13 @@ module Fission
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def execute
|
10
|
-
unless args.count == 1
|
10
|
+
unless @args.count == 1
|
11
11
|
Fission.ui.output self.class.help
|
12
12
|
Fission.ui.output ""
|
13
13
|
Fission.ui.output_and_exit "Incorrect arguments for stop command", 1
|
14
14
|
end
|
15
15
|
|
16
|
-
vm_name = args.first
|
16
|
+
vm_name = @args.first
|
17
17
|
|
18
18
|
unless Fission::VM.exists? vm_name
|
19
19
|
Fission.ui.output_and_exit "Unable to find the VM #{vm_name} (#{Fission::VM.path(vm_name)})", 1
|
@@ -4,34 +4,50 @@ module Fission
|
|
4
4
|
|
5
5
|
def initialize(args=[])
|
6
6
|
super
|
7
|
+
@options.all = false
|
7
8
|
end
|
8
9
|
|
9
10
|
def execute
|
10
|
-
|
11
|
+
option_parser.parse! @args
|
12
|
+
|
13
|
+
if @args.count != 1 && !@options.all
|
11
14
|
Fission.ui.output self.class.help
|
12
15
|
Fission.ui.output ""
|
13
16
|
Fission.ui.output_and_exit "Incorrect arguments for suspend command", 1
|
14
17
|
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
Fission.ui.output_and_exit "Unable to find the VM #{vm_name} (#{Fission::VM.path(vm_name)})", 1
|
19
|
+
vms_to_suspend.each do |vm_name|
|
20
|
+
Fission.ui.output "Suspending '#{vm_name}'"
|
21
|
+
Fission::VM.new(vm_name).suspend
|
20
22
|
end
|
23
|
+
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
def vms_to_suspend
|
26
|
+
if @options.all
|
27
|
+
vms_to_suspend = VM.all_running
|
28
|
+
else
|
29
|
+
vm_name = @args.first
|
30
|
+
unless Fission::VM.exists? vm_name
|
31
|
+
Fission.ui.output ''
|
32
|
+
Fission.ui.output_and_exit "Unable to find the VM #{vm_name} (#{Fission::VM.path(vm_name)})", 1
|
33
|
+
end
|
34
|
+
|
35
|
+
unless VM.all_running.include?(vm_name)
|
36
|
+
Fission.ui.output ''
|
37
|
+
Fission.ui.output_and_exit "VM '#{vm_name}' is not running", 1
|
38
|
+
end
|
39
|
+
|
40
|
+
vms_to_suspend = [vm_name]
|
25
41
|
end
|
26
|
-
|
27
|
-
Fission.ui.output "suspending '#{vm_name}'"
|
28
|
-
@vm = Fission::VM.new vm_name
|
29
|
-
@vm.suspend
|
30
42
|
end
|
31
43
|
|
32
44
|
def option_parser
|
33
45
|
optparse = OptionParser.new do |opts|
|
34
|
-
opts.banner = "\nsuspend usage: fission suspend vm"
|
46
|
+
opts.banner = "\nsuspend usage: fission suspend [vm | --all]"
|
47
|
+
|
48
|
+
opts.on '--all', 'Suspend all running VMs' do
|
49
|
+
@options.all = true
|
50
|
+
end
|
35
51
|
end
|
36
52
|
|
37
53
|
optparse
|
data/lib/fission/config.rb
CHANGED
@@ -14,6 +14,8 @@ module Fission
|
|
14
14
|
|
15
15
|
@attributes['vmrun_bin'] = '/Library/Application Support/VMware Fusion/vmrun'
|
16
16
|
@attributes['vmrun_cmd'] = "#{@attributes['vmrun_bin'].gsub(' ', '\ ')} -T fusion"
|
17
|
+
@attributes['plist_file'] = File.expand_path('~/Library/Preferences/com.vmware.fusion.plist')
|
18
|
+
@attributes['gui_bin'] = File.expand_path('/Applications/VMware Fusion.app/Contents/MacOS/vmware')
|
17
19
|
end
|
18
20
|
|
19
21
|
private
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Fission
|
2
|
+
class Fusion
|
3
|
+
|
4
|
+
def self.is_running?
|
5
|
+
command = "ps -ef | grep -v grep | grep -c "
|
6
|
+
command << "#{Fission.config.attributes['gui_bin'].gsub(' ', '\ ')} 2>&1"
|
7
|
+
output = `#{command}`
|
8
|
+
|
9
|
+
output.strip.to_i > 0 ? true : false
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Fission
|
2
|
+
class Metadata
|
3
|
+
|
4
|
+
require 'cfpropertylist'
|
5
|
+
|
6
|
+
attr_accessor :content
|
7
|
+
|
8
|
+
def self.delete_vm_info(vm_path)
|
9
|
+
metadata = new
|
10
|
+
metadata.load
|
11
|
+
metadata.delete_vm_restart_document(vm_path)
|
12
|
+
metadata.delete_vm_favorite_entry(vm_path)
|
13
|
+
metadata.save
|
14
|
+
end
|
15
|
+
|
16
|
+
def load
|
17
|
+
raw_data = CFPropertyList::List.new :file => Fission.config.attributes['plist_file']
|
18
|
+
@content = CFPropertyList.native_types raw_data.value
|
19
|
+
end
|
20
|
+
|
21
|
+
def save
|
22
|
+
new_content = CFPropertyList::List.new
|
23
|
+
new_content.value = CFPropertyList.guess @content
|
24
|
+
new_content.save Fission.config.attributes['plist_file'],
|
25
|
+
CFPropertyList::List::FORMAT_BINARY
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete_vm_restart_document(vm_path)
|
29
|
+
if @content.has_key?('PLRestartDocumentPaths')
|
30
|
+
@content['PLRestartDocumentPaths'].delete_if { |p| p == vm_path }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_vm_favorite_entry(vm_path)
|
35
|
+
@content['VMFavoritesListDefaults2'].delete_if { |vm| vm['path'] == vm_path }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/lib/fission/version.rb
CHANGED
data/lib/fission/vm.rb
CHANGED
@@ -6,8 +6,52 @@ module Fission
|
|
6
6
|
@name = name
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
command = "#{Fission.config.attributes['vmrun_cmd']}
|
9
|
+
def create_snapshot(name)
|
10
|
+
command = "#{Fission.config.attributes['vmrun_cmd']} snapshot #{conf_file.gsub ' ', '\ '} \"#{name}\" 2>&1"
|
11
|
+
output = `#{command}`
|
12
|
+
|
13
|
+
if $?.exitstatus == 0
|
14
|
+
Fission.ui.output "Snapshot '#{name}' created"
|
15
|
+
else
|
16
|
+
Fission.ui.output "There was an error creating the snapshot."
|
17
|
+
Fission.ui.output_and_exit "The error was:\n#{output}", 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def revert_to_snapshot(name)
|
22
|
+
command = "#{Fission.config.attributes['vmrun_cmd']} revertToSnapshot #{conf_file.gsub ' ', '\ '} \"#{name}\" 2>&1"
|
23
|
+
output = `#{command}`
|
24
|
+
|
25
|
+
if $?.exitstatus == 0
|
26
|
+
Fission.ui.output "Reverted to snapshot '#{name}'"
|
27
|
+
else
|
28
|
+
Fission.ui.output "There was an error reverting to the snapshot."
|
29
|
+
Fission.ui.output_and_exit "The error was:\n#{output}", 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def snapshots
|
34
|
+
command = "#{Fission.config.attributes['vmrun_cmd']} listSnapshots #{conf_file.gsub ' ', '\ '} 2>&1"
|
35
|
+
output = `#{command}`
|
36
|
+
|
37
|
+
if $?.exitstatus == 0
|
38
|
+
snaps = output.split("\n").select { |s| !s.include? 'Total snapshots:' }
|
39
|
+
snaps.map { |s| s.strip }
|
40
|
+
else
|
41
|
+
Fission.ui.output "There was an error getting the list of snapshots."
|
42
|
+
Fission.ui.output_and_exit "The error was:\n#{output}", 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def start(args={})
|
47
|
+
command = "#{Fission.config.attributes['vmrun_cmd']} start #{conf_file.gsub ' ', '\ '} "
|
48
|
+
|
49
|
+
if !args[:headless].blank? && args[:headless]
|
50
|
+
command << "nogui 2>&1"
|
51
|
+
else
|
52
|
+
command << "gui 2>&1"
|
53
|
+
end
|
54
|
+
|
11
55
|
output = `#{command}`
|
12
56
|
|
13
57
|
if $?.exitstatus == 0
|
@@ -40,7 +84,24 @@ module Fission
|
|
40
84
|
end
|
41
85
|
|
42
86
|
def conf_file
|
43
|
-
File.join
|
87
|
+
vmx_path = File.join(self.class.path(@name), "*.vmx")
|
88
|
+
conf_files = Dir.glob(vmx_path)
|
89
|
+
|
90
|
+
case conf_files.count
|
91
|
+
when 0
|
92
|
+
Fission.ui.output_and_exit "Unable to find a config file for VM '#{@name}' (in '#{vmx_path}')", 1
|
93
|
+
when 1
|
94
|
+
conf_files.first
|
95
|
+
else
|
96
|
+
if conf_files.include?(File.join(File.dirname(vmx_path), "#{@name}.vmx"))
|
97
|
+
File.join(File.dirname(vmx_path), "#{@name}.vmx")
|
98
|
+
else
|
99
|
+
output = "Multiple config files found for VM '#{@name}' ("
|
100
|
+
output << conf_files.sort.map { |f| "'#{File.basename(f)}'" }.join(', ')
|
101
|
+
output << " in '#{File.dirname(vmx_path)}')"
|
102
|
+
Fission.ui.output_and_exit output, 1
|
103
|
+
end
|
104
|
+
end
|
44
105
|
end
|
45
106
|
|
46
107
|
def self.all
|
@@ -56,21 +117,15 @@ module Fission
|
|
56
117
|
|
57
118
|
output = `#{command}`
|
58
119
|
|
59
|
-
vms = []
|
60
|
-
|
61
120
|
if $?.exitstatus == 0
|
62
|
-
output.split("\n").
|
63
|
-
|
64
|
-
if File.exists?(vm) && (File.extname(vm) == '.vmx')
|
65
|
-
vms << File.basename(vm, '.vmx')
|
66
|
-
end
|
67
|
-
end
|
121
|
+
vms = output.split("\n").select do |vm|
|
122
|
+
vm.include?('.vmx') && File.exists?(vm) && File.extname(vm) == '.vmx'
|
68
123
|
end
|
124
|
+
|
125
|
+
vms.map { |vm| File.basename(File.dirname(vm), '.vmwarevm') }
|
69
126
|
else
|
70
127
|
Fission.ui.output_and_exit "Unable to determine the list of running VMs", 1
|
71
128
|
end
|
72
|
-
|
73
|
-
vms
|
74
129
|
end
|
75
130
|
|
76
131
|
def self.exists?(vm_name)
|
@@ -90,15 +145,45 @@ module Fission
|
|
90
145
|
update_config source_vm, target_vm
|
91
146
|
end
|
92
147
|
|
148
|
+
def self.delete(vm_name)
|
149
|
+
Fission.ui.output "Deleting vm #{vm_name}"
|
150
|
+
FileUtils.rm_rf path(vm_name)
|
151
|
+
Fission::Metadata.delete_vm_info(path(vm_name))
|
152
|
+
end
|
153
|
+
|
93
154
|
private
|
94
155
|
def self.rename_vm_files(from, to)
|
95
156
|
files_to_rename(from, to).each do |file|
|
96
|
-
|
157
|
+
text_to_replace = File.basename(file, File.extname(file))
|
158
|
+
|
159
|
+
if File.extname(file) == '.vmdk'
|
160
|
+
if file.match /\-s\d+\.vmdk/
|
161
|
+
text_to_replace = file.partition(/\-s\d+.vmdk/).first
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
unless File.exists?(File.join(path(to), file.gsub(text_to_replace, to)))
|
166
|
+
FileUtils.mv File.join(path(to), file),
|
167
|
+
File.join(path(to), file.gsub(text_to_replace, to))
|
168
|
+
end
|
97
169
|
end
|
98
170
|
end
|
99
171
|
|
100
172
|
def self.files_to_rename(from, to)
|
101
|
-
|
173
|
+
files_which_match_source_vm = []
|
174
|
+
other_files = []
|
175
|
+
|
176
|
+
Dir.entries(path(to)).each do |f|
|
177
|
+
unless f == '.' || f == '..'
|
178
|
+
f.include?(from) ? files_which_match_source_vm << f : other_files << f
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
files_which_match_source_vm + other_files
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.vm_file_extensions
|
186
|
+
['.nvram', '.vmdk', '.vmem', '.vmsd', '.vmss', '.vmx', '.vmxf']
|
102
187
|
end
|
103
188
|
|
104
189
|
def self.update_config(from, to)
|
data/spec/fission/cli_spec.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
require File.expand_path('../../spec_helper.rb', __FILE__)
|
2
2
|
|
3
3
|
describe Fission::CLI do
|
4
|
-
before
|
4
|
+
before do
|
5
5
|
@string_io = StringIO.new
|
6
6
|
Fission.stub!(:ui).and_return(Fission::UI.new(@string_io))
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'self.commands' do
|
10
10
|
it 'should return the list of commands' do
|
11
|
-
Fission::CLI.commands.should == ['clone', '
|
11
|
+
Fission::CLI.commands.should == ['clone', 'delete', 'snapshot create',
|
12
|
+
'snapshot list', 'snapshot revert',
|
13
|
+
'start', 'status', 'stop', 'suspend']
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
17
|
describe 'execute' do
|
16
|
-
|
17
18
|
describe 'with no arguments' do
|
18
19
|
it 'should output the usage info' do
|
19
20
|
lambda {
|
@@ -35,7 +36,6 @@ describe Fission::CLI do
|
|
35
36
|
|
36
37
|
end
|
37
38
|
end
|
38
|
-
|
39
39
|
end
|
40
40
|
|
41
41
|
describe '-h or --help' do
|
@@ -48,11 +48,10 @@ describe Fission::CLI do
|
|
48
48
|
@string_io.string.should match /Usage/
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
52
51
|
end
|
53
52
|
|
54
53
|
describe 'with the sub command' do
|
55
|
-
before
|
54
|
+
before do
|
56
55
|
@cmd_mock = mock('cmd')
|
57
56
|
@cmd_mock.should_receive(:execute)
|
58
57
|
end
|
@@ -60,23 +59,74 @@ describe Fission::CLI do
|
|
60
59
|
describe 'clone' do
|
61
60
|
it "should try to clone the vm" do
|
62
61
|
Fission::Command::Clone.stub!(:help).and_return('')
|
63
|
-
Fission::Command::Clone.should_receive(:new).with(['foo', 'bar']).
|
62
|
+
Fission::Command::Clone.should_receive(:new).with(['foo', 'bar']).
|
63
|
+
and_return(@cmd_mock)
|
64
64
|
Fission::CLI.execute ['clone', 'foo', 'bar']
|
65
65
|
end
|
66
|
+
|
67
|
+
it 'should try to clone the vm and start it' do
|
68
|
+
Fission::Command::Clone.stub!(:help).and_return('')
|
69
|
+
Fission::Command::Clone.should_receive(:new).with(['foo', 'bar', '--start']).
|
70
|
+
and_return(@cmd_mock)
|
71
|
+
Fission::CLI.execute ['clone', 'foo', 'bar', '--start']
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'snapshot create' do
|
76
|
+
it "should create a snapshot" do
|
77
|
+
Fission::Command::SnapshotCreate.stub!(:help).and_return('')
|
78
|
+
Fission::Command::SnapshotCreate.should_receive(:new).
|
79
|
+
with(['foo', 'snap1']).
|
80
|
+
and_return(@cmd_mock)
|
81
|
+
Fission::CLI.execute ['snapshot', 'create', 'foo', 'snap1']
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'snapshot list' do
|
86
|
+
it "should list the snapshots" do
|
87
|
+
Fission::Command::SnapshotList.stub!(:help).and_return('')
|
88
|
+
Fission::Command::SnapshotList.should_receive(:new).
|
89
|
+
with([]).
|
90
|
+
and_return(@cmd_mock)
|
91
|
+
Fission::CLI.execute ['snapshot', 'list']
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'snapshot revert' do
|
96
|
+
it "should revert to the snapshots" do
|
97
|
+
Fission::Command::SnapshotRevert.stub!(:help).and_return('')
|
98
|
+
Fission::Command::SnapshotRevert.should_receive(:new).
|
99
|
+
with(['foo', 'snap1']).
|
100
|
+
and_return(@cmd_mock)
|
101
|
+
Fission::CLI.execute ['snapshot', 'revert', 'foo', 'snap1']
|
102
|
+
end
|
66
103
|
end
|
67
104
|
|
68
105
|
describe 'start' do
|
69
106
|
it "should try to start the vm" do
|
70
107
|
Fission::Command::Start.stub!(:help).and_return('')
|
71
|
-
Fission::Command::Start.should_receive(:new).
|
108
|
+
Fission::Command::Start.should_receive(:new).
|
109
|
+
with(['foo']).
|
110
|
+
and_return(@cmd_mock)
|
72
111
|
Fission::CLI.execute ['start', 'foo']
|
73
112
|
end
|
113
|
+
|
114
|
+
it 'should try to start the vm headless' do
|
115
|
+
Fission::Command::Start.stub!(:help).and_return('')
|
116
|
+
Fission::Command::Start.should_receive(:new).
|
117
|
+
with(['foo', '--headless']).
|
118
|
+
and_return(@cmd_mock)
|
119
|
+
Fission::CLI.execute ['start', 'foo', '--headless']
|
120
|
+
|
121
|
+
end
|
74
122
|
end
|
75
123
|
|
76
124
|
describe 'status' do
|
77
125
|
it "should try to get the status for all VMs" do
|
78
126
|
Fission::Command::Status.stub!(:help).and_return('')
|
79
|
-
Fission::Command::Status.should_receive(:new).
|
127
|
+
Fission::Command::Status.should_receive(:new).
|
128
|
+
with([]).
|
129
|
+
and_return(@cmd_mock)
|
80
130
|
Fission::CLI.execute ['status']
|
81
131
|
end
|
82
132
|
end
|
@@ -84,7 +134,9 @@ describe Fission::CLI do
|
|
84
134
|
describe 'stop' do
|
85
135
|
it "should try to stop the vm" do
|
86
136
|
Fission::Command::Stop.stub!(:help).and_return('')
|
87
|
-
Fission::Command::Stop.should_receive(:new).
|
137
|
+
Fission::Command::Stop.should_receive(:new).
|
138
|
+
with(['foo']).
|
139
|
+
and_return(@cmd_mock)
|
88
140
|
Fission::CLI.execute ['stop', 'foo']
|
89
141
|
end
|
90
142
|
end
|
@@ -92,9 +144,37 @@ describe Fission::CLI do
|
|
92
144
|
describe 'suspend' do
|
93
145
|
it "should try to suspend the vm" do
|
94
146
|
Fission::Command::Suspend.stub!(:help).and_return('')
|
95
|
-
Fission::Command::Suspend.should_receive(:new).
|
147
|
+
Fission::Command::Suspend.should_receive(:new).
|
148
|
+
with(['foo']).
|
149
|
+
and_return(@cmd_mock)
|
96
150
|
Fission::CLI.execute ['suspend', 'foo']
|
97
151
|
end
|
152
|
+
|
153
|
+
it 'should try to suspend all of vms' do
|
154
|
+
Fission::Command::Suspend.stub!(:help).and_return('')
|
155
|
+
Fission::Command::Suspend.should_receive(:new).
|
156
|
+
with(['--all']).
|
157
|
+
and_return(@cmd_mock)
|
158
|
+
Fission::CLI.execute ['suspend', '--all']
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe 'delete' do
|
163
|
+
it "should try to delete the vm" do
|
164
|
+
Fission::Command::Delete.stub!(:help).and_return('')
|
165
|
+
Fission::Command::Delete.should_receive(:new).
|
166
|
+
with(['foo']).
|
167
|
+
and_return(@cmd_mock)
|
168
|
+
Fission::CLI.execute ['delete', 'foo']
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should try to force delete the vm' do
|
172
|
+
Fission::Command::Delete.stub!(:help).and_return('')
|
173
|
+
Fission::Command::Delete.should_receive(:new).
|
174
|
+
with(['foo', '--force']).
|
175
|
+
and_return(@cmd_mock)
|
176
|
+
Fission::CLI.execute ['delete', 'foo', '--force']
|
177
|
+
end
|
98
178
|
end
|
99
179
|
end
|
100
180
|
|