fission 0.2.0 → 0.3.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|