fission 0.4.0 → 0.5.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/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +12 -3
- data/README.md +45 -19
- data/bin/fission +1 -1
- data/fission.gemspec +3 -2
- data/lib/fission.rb +15 -0
- data/lib/fission/action/shell_executor.rb +37 -0
- data/lib/fission/action/snapshot/creator.rb +81 -0
- data/lib/fission/action/snapshot/deleter.rb +85 -0
- data/lib/fission/action/snapshot/lister.rb +90 -0
- data/lib/fission/action/snapshot/reverter.rb +81 -0
- data/lib/fission/action/vm/cloner.rb +191 -0
- data/lib/fission/action/vm/deleter.rb +73 -0
- data/lib/fission/action/vm/lister.rb +138 -0
- data/lib/fission/action/vm/starter.rb +88 -0
- data/lib/fission/action/vm/stopper.rb +79 -0
- data/lib/fission/action/vm/suspender.rb +68 -0
- data/lib/fission/cli.rb +21 -117
- data/lib/fission/command.rb +39 -0
- data/lib/fission/command/clone.rb +11 -6
- data/lib/fission/command/delete.rb +11 -6
- data/lib/fission/command/info.rb +62 -0
- data/lib/fission/command/snapshot_create.rb +9 -3
- data/lib/fission/command/snapshot_delete.rb +38 -0
- data/lib/fission/command/snapshot_list.rb +9 -3
- data/lib/fission/command/snapshot_revert.rb +9 -3
- data/lib/fission/command/start.rb +11 -6
- data/lib/fission/command/status.rb +9 -1
- data/lib/fission/command/stop.rb +9 -3
- data/lib/fission/command/suspend.rb +11 -6
- data/lib/fission/command_helpers.rb +18 -4
- data/lib/fission/command_line_parser.rb +189 -0
- data/lib/fission/config.rb +1 -1
- data/lib/fission/fusion.rb +3 -4
- data/lib/fission/lease.rb +2 -1
- data/lib/fission/metadata.rb +6 -1
- data/lib/fission/response.rb +17 -9
- data/lib/fission/version.rb +1 -1
- data/lib/fission/vm.rb +142 -382
- data/lib/fission/vm_configuration.rb +79 -0
- data/spec/fission/action/execute_shell_command_spec.rb +25 -0
- data/spec/fission/action/snapshot/creator_spec.rb +77 -0
- data/spec/fission/action/snapshot/deleter_spec.rb +84 -0
- data/spec/fission/action/snapshot/lister_spec.rb +67 -0
- data/spec/fission/action/snapshot/reverter_spec.rb +76 -0
- data/spec/fission/action/vm/cloner_spec.rb +198 -0
- data/spec/fission/action/vm/deleter_spec.rb +79 -0
- data/spec/fission/action/vm/lister_spec.rb +164 -0
- data/spec/fission/action/vm/starter_spec.rb +88 -0
- data/spec/fission/action/vm/stopper_spec.rb +71 -0
- data/spec/fission/action/vm/suspender_spec.rb +59 -0
- data/spec/fission/cli_spec.rb +32 -157
- data/spec/fission/command/clone_spec.rb +9 -3
- data/spec/fission/command/delete_spec.rb +11 -3
- data/spec/fission/command/info_spec.rb +130 -0
- data/spec/fission/command/snapshot_create_spec.rb +11 -3
- data/spec/fission/command/snapshot_delete_spec.rb +74 -0
- data/spec/fission/command/snapshot_list_spec.rb +11 -3
- data/spec/fission/command/snapshot_revert_spec.rb +11 -3
- data/spec/fission/command/start_spec.rb +11 -3
- data/spec/fission/command/status_spec.rb +16 -5
- data/spec/fission/command/stop_spec.rb +11 -3
- data/spec/fission/command/suspend_spec.rb +11 -3
- data/spec/fission/command_helpers_spec.rb +27 -5
- data/spec/fission/command_line_parser_spec.rb +267 -0
- data/spec/fission/command_spec.rb +16 -1
- data/spec/fission/config_spec.rb +3 -3
- data/spec/fission/fusion_spec.rb +11 -6
- data/spec/fission/lease_spec.rb +81 -45
- data/spec/fission/metadata_spec.rb +29 -6
- data/spec/fission/response_spec.rb +20 -9
- data/spec/fission/ui_spec.rb +1 -1
- data/spec/fission/vm_configuration_spec.rb +132 -0
- data/spec/fission/vm_spec.rb +393 -750
- data/spec/helpers/command_helpers.rb +1 -1
- metadata +93 -15
- data/.rvmrc +0 -1
@@ -0,0 +1,189 @@
|
|
1
|
+
module Fission
|
2
|
+
|
3
|
+
class CommandLineParser
|
4
|
+
|
5
|
+
# Internal: Creates a new Fission::CommandLineParser object.
|
6
|
+
#
|
7
|
+
# args - The command line arguments to parse. This is expected to be in the
|
8
|
+
# same format of ARGV (Array) (default: ARGV).
|
9
|
+
#
|
10
|
+
# Examples:
|
11
|
+
#
|
12
|
+
# CommandLineParser.new ['foo', 'bar']
|
13
|
+
#
|
14
|
+
# CommandLineParser.new
|
15
|
+
#
|
16
|
+
# Returns a Fission::CommandLineParser object.
|
17
|
+
def initialize(args=ARGV)
|
18
|
+
@args = args
|
19
|
+
|
20
|
+
gather_commands_and_summaries
|
21
|
+
|
22
|
+
setup_options_parser
|
23
|
+
end
|
24
|
+
|
25
|
+
# Internal: Parses the command line arguments. If the arguments are
|
26
|
+
# invalid, the appropriate help will be output and then will exit. If the
|
27
|
+
# arguments are valid, then the @command variable will be set to a new
|
28
|
+
# instance of the determined command class.
|
29
|
+
#
|
30
|
+
# Examples:
|
31
|
+
#
|
32
|
+
# @command_line_parser.parse
|
33
|
+
#
|
34
|
+
# Returns nothing.
|
35
|
+
def parse
|
36
|
+
@options_parser.order! @args
|
37
|
+
|
38
|
+
determine_command_provided
|
39
|
+
self
|
40
|
+
rescue OptionParser::InvalidOption => e
|
41
|
+
ui.output e
|
42
|
+
show_all_help
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
|
46
|
+
# Internal: Accessor for an instance of the determined command. This is set
|
47
|
+
# by running the parse method.
|
48
|
+
#
|
49
|
+
# Examples:
|
50
|
+
#
|
51
|
+
# @command_line_parser.command
|
52
|
+
#
|
53
|
+
# Returns an instance of the determined command if the arguments are valid.
|
54
|
+
# Returns nil if the parse command has not yet been run.
|
55
|
+
def command
|
56
|
+
@command
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
# Internal: Sets up the base option parser.
|
61
|
+
#
|
62
|
+
# Examples:
|
63
|
+
#
|
64
|
+
# @cli.setup_option_parser
|
65
|
+
#
|
66
|
+
# Returns nothing. This will set the @option_parser instance variable.
|
67
|
+
def setup_options_parser
|
68
|
+
@options_parser = OptionParser.new do |opts|
|
69
|
+
opts.banner = "\nUsage: fission [options] COMMAND [arguments]"
|
70
|
+
|
71
|
+
opts.on_head('-v', '--version', 'Output the version of fission') do
|
72
|
+
ui.output VERSION
|
73
|
+
exit 0
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.on_head('-h', '--help', 'Displays this message') do
|
77
|
+
show_all_help
|
78
|
+
exit 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Internal: Provides the help of all of the known commands.
|
84
|
+
#
|
85
|
+
# Examples
|
86
|
+
#
|
87
|
+
# @cli.commands_help
|
88
|
+
#
|
89
|
+
# Outputs the summary text for all known commands.
|
90
|
+
def commands_help
|
91
|
+
longest_cmd = @commands.inject do |longest, cmd_name|
|
92
|
+
longest.length > cmd_name.length ? longest : cmd_name
|
93
|
+
end
|
94
|
+
|
95
|
+
ui.output "\nCommands:"
|
96
|
+
|
97
|
+
Hash[@command_names_and_summaries.sort].each_pair do |name, summary|
|
98
|
+
ui.output_printf "%-#{longest_cmd.length}s %s\n", name, summary
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Internal: Determines all of the available commands and their summaries.
|
103
|
+
#
|
104
|
+
# Examples
|
105
|
+
#
|
106
|
+
# @cli.command_names_and_summaries
|
107
|
+
# # => { 'clone' => 'Clones a VM', 'stop' => 'Stops a VM' }
|
108
|
+
#
|
109
|
+
# Returns nothing. This will set the @command_names_and_summaries instance
|
110
|
+
# variable with the result.
|
111
|
+
def gather_commands_and_summaries
|
112
|
+
@command_names_and_summaries = Command.descendants.inject({}) do |result, klass|
|
113
|
+
cmd = klass.new
|
114
|
+
result[cmd.command_name] = cmd.summary
|
115
|
+
result
|
116
|
+
end
|
117
|
+
|
118
|
+
@commands = @command_names_and_summaries.keys.sort
|
119
|
+
end
|
120
|
+
|
121
|
+
# Internal: Determines the command that has been provided. If it is
|
122
|
+
# determined that an invalid command is provided, then the help/usage will
|
123
|
+
# be displayed and it will exit.
|
124
|
+
#
|
125
|
+
# Examples:
|
126
|
+
#
|
127
|
+
# @cli.determine_command_to_execute
|
128
|
+
#
|
129
|
+
# Returns nothing. This will set the @command instance variable to an instance
|
130
|
+
# of the appropriate command class (assuming it is valid).
|
131
|
+
def determine_command_provided
|
132
|
+
if @commands.include? @args.first
|
133
|
+
@command = Command.const_get(@args.first.capitalize).new @args.drop 1
|
134
|
+
elsif is_snapshot_command?
|
135
|
+
klass = @args.take(2).map {|c| c.capitalize}.join('')
|
136
|
+
@command = Command.const_get(klass).new @args.drop 2
|
137
|
+
else
|
138
|
+
show_all_help
|
139
|
+
exit 1
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Internal: Determines if the provided command is a snapshot related
|
144
|
+
# command. This will use the @args instance variable to make the
|
145
|
+
# determination.
|
146
|
+
#
|
147
|
+
# Examples
|
148
|
+
#
|
149
|
+
# @cli.is_snapshot_command? ['foo', 'bar']
|
150
|
+
# # => false
|
151
|
+
#
|
152
|
+
# @cli.is_snapshot_command? ['snapshot', 'list']
|
153
|
+
# # => true
|
154
|
+
#
|
155
|
+
# Returns a Boolean of whether a snapshot command was given or not.
|
156
|
+
def is_snapshot_command?
|
157
|
+
@args.first == 'snapshot' &&
|
158
|
+
@args.count > 1 &&
|
159
|
+
@commands.include?(@args.take(2).join(' '))
|
160
|
+
end
|
161
|
+
|
162
|
+
# Internal: Outputs the usage as well as the known commands and their
|
163
|
+
# summaries.
|
164
|
+
#
|
165
|
+
# Examples
|
166
|
+
#
|
167
|
+
# @cli.show_all_help
|
168
|
+
# # => 'fission options command arguments ....'
|
169
|
+
#
|
170
|
+
# Returns nothing.
|
171
|
+
def show_all_help
|
172
|
+
ui.output @options_parser
|
173
|
+
commands_help
|
174
|
+
end
|
175
|
+
|
176
|
+
# Internal: Helper method for outputting text to the ui
|
177
|
+
#
|
178
|
+
# Examples
|
179
|
+
#
|
180
|
+
# @cli.ui.output 'foo'
|
181
|
+
#
|
182
|
+
# Returns a UI instance.
|
183
|
+
def ui
|
184
|
+
@ui ||= UI.new
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
data/lib/fission/config.rb
CHANGED
@@ -27,7 +27,7 @@ module Fission
|
|
27
27
|
|
28
28
|
load_from_file
|
29
29
|
|
30
|
-
@attributes['vmrun_cmd'] = "#{@attributes['vmrun_bin']
|
30
|
+
@attributes['vmrun_cmd'] = "'#{@attributes['vmrun_bin']}' -T fusion"
|
31
31
|
end
|
32
32
|
|
33
33
|
# Public: Helper method to access config atributes. This is a shortcut for
|
data/lib/fission/fusion.rb
CHANGED
@@ -11,10 +11,9 @@ module Fission
|
|
11
11
|
# Returns a Boolean.
|
12
12
|
def self.running?
|
13
13
|
command = "ps -ef | grep -v grep | grep -c "
|
14
|
-
command << "#{Fission.config['gui_bin']
|
15
|
-
|
16
|
-
|
17
|
-
output.strip.to_i > 0
|
14
|
+
command << "'#{Fission.config['gui_bin']}' 2>&1"
|
15
|
+
command_executor = Fission::Action::ShellExecutor.new command
|
16
|
+
command_executor.execute['output'].strip.to_i > 0
|
18
17
|
end
|
19
18
|
|
20
19
|
end
|
data/lib/fission/lease.rb
CHANGED
@@ -97,7 +97,8 @@ module Fission
|
|
97
97
|
|
98
98
|
if all_response.successful?
|
99
99
|
response = Response.new :code => 0
|
100
|
-
|
100
|
+
leases = all_response.data.find_all { |l| l.mac_address == mac_address }
|
101
|
+
response.data = leases.sort_by { |l| l.end }.last
|
101
102
|
else
|
102
103
|
response = all_response
|
103
104
|
end
|
data/lib/fission/metadata.rb
CHANGED
@@ -85,7 +85,12 @@ module Fission
|
|
85
85
|
#
|
86
86
|
# Returns nothing.
|
87
87
|
def delete_vm_favorite_entry(vm_path)
|
88
|
-
@content
|
88
|
+
if @content.has_key?('VMFavoritesListDefaults2')
|
89
|
+
@content['VMFavoritesListDefaults2'].delete_if { |vm| vm['path'] == vm_path }
|
90
|
+
end
|
91
|
+
if @content.has_key?('fusionInitialSessions')
|
92
|
+
@content['fusionInitialSessions'].delete_if {|vm| vm['documentPath'] == vm_path}
|
93
|
+
end
|
89
94
|
end
|
90
95
|
|
91
96
|
end
|
data/lib/fission/response.rb
CHANGED
@@ -57,18 +57,26 @@ module Fission
|
|
57
57
|
@code == 0
|
58
58
|
end
|
59
59
|
|
60
|
-
#
|
61
|
-
# command
|
60
|
+
# Internal: Helper method to create a new Response object when using
|
61
|
+
# executing a command through Fission::Action::ShellExecutor.
|
62
62
|
#
|
63
|
-
#
|
63
|
+
# shell_execute_result - This should be the result of running 'execute' on
|
64
|
+
# a ShellExecutor object.
|
65
|
+
#
|
66
|
+
# Examples:
|
67
|
+
#
|
68
|
+
# Response.from_shell_executor shell_execute_result
|
64
69
|
#
|
65
70
|
# Returns a Response.
|
66
|
-
# The
|
67
|
-
#
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
response
|
71
|
+
# The code attribute of the Response will be set to the exit_status
|
72
|
+
# attribute of the provided process_status data. The message attribute of
|
73
|
+
# the Response will be set to the output of the provided data if, and only
|
74
|
+
# if, the Response is unsuccessful.
|
75
|
+
def self.from_shell_executor(shell_execute_result)
|
76
|
+
response = new :code => shell_execute_result['process_status'].exitstatus
|
77
|
+
unless response.successful?
|
78
|
+
response.message = shell_execute_result['output']
|
79
|
+
end
|
72
80
|
response
|
73
81
|
end
|
74
82
|
|
data/lib/fission/version.rb
CHANGED
data/lib/fission/vm.rb
CHANGED
@@ -21,33 +21,23 @@ module Fission
|
|
21
21
|
# If successful, the Response's data attribute will be nil.
|
22
22
|
# If there is an error, an unsuccessful Response will be returned.
|
23
23
|
def create_snapshot(name)
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
running_response = running?
|
29
|
-
return running_response unless running_response.successful?
|
30
|
-
|
31
|
-
unless running_response.data
|
32
|
-
message = 'The VM must be running in order to take a snapshot.'
|
33
|
-
return Response.new :code => 1, :message => message
|
34
|
-
end
|
35
|
-
|
36
|
-
conf_file_response = conf_file
|
37
|
-
return conf_file_response unless conf_file_response.successful?
|
38
|
-
|
39
|
-
snapshots_response = snapshots
|
40
|
-
return snapshots_response unless snapshots_response.successful?
|
41
|
-
|
42
|
-
if snapshots_response.data.include? name
|
43
|
-
message = "There is already a snapshot named '#{name}'."
|
44
|
-
return Response.new :code => 1, :message => message
|
45
|
-
end
|
46
|
-
|
47
|
-
command = "#{vmrun_cmd} snapshot "
|
48
|
-
command << "#{conf_file_response.data} \"#{name}\" 2>&1"
|
24
|
+
Fission::Action::Snapshot::Creator.new(self).create_snapshot(name)
|
25
|
+
end
|
49
26
|
|
50
|
-
|
27
|
+
# Public: Deletes a snapshot for a VM. The snapshot to delete must exist.
|
28
|
+
# If the Fusion GUI is running, then the VM must also be running.
|
29
|
+
#
|
30
|
+
# name - The name of the snapshot to delete.
|
31
|
+
#
|
32
|
+
# Examples
|
33
|
+
#
|
34
|
+
# @vm.delete_snapshot('foo_snap_1')
|
35
|
+
#
|
36
|
+
# Returns a Response with the result.
|
37
|
+
# If successful, the Response's data attribute will be nil.
|
38
|
+
# If there is an error, an unsuccessful Response will be returned.
|
39
|
+
def delete_snapshot(name)
|
40
|
+
Fission::Action::Snapshot::Deleter.new(self).delete_snapshot(name)
|
51
41
|
end
|
52
42
|
|
53
43
|
# Public: Reverts the VM to the specified snapshot. The snapshot to revert
|
@@ -63,32 +53,7 @@ module Fission
|
|
63
53
|
# If successful, the Response's data attribute will be nil.
|
64
54
|
# If there is an error, an unsuccessful Response will be returned.
|
65
55
|
def revert_to_snapshot(name)
|
66
|
-
|
67
|
-
return Response.new :code => 1, :message => 'VM does not exist'
|
68
|
-
end
|
69
|
-
|
70
|
-
if Fusion.running?
|
71
|
-
message = 'It looks like the Fusion GUI is currently running. '
|
72
|
-
message << 'A VM cannot be reverted to a snapshot when the Fusion GUI is running. '
|
73
|
-
message << 'Exit the Fusion GUI and try again.'
|
74
|
-
return Response.new :code => 1, :message => message
|
75
|
-
end
|
76
|
-
|
77
|
-
conf_file_response = conf_file
|
78
|
-
return conf_file_response unless conf_file_response.successful?
|
79
|
-
|
80
|
-
snapshots_response = snapshots
|
81
|
-
return snapshots_response unless snapshots_response.successful?
|
82
|
-
|
83
|
-
unless snapshots_response.data.include? name
|
84
|
-
message = "Unable to find a snapshot named '#{name}'."
|
85
|
-
return Response.new :code => 1, :message => message
|
86
|
-
end
|
87
|
-
|
88
|
-
command = "#{vmrun_cmd} revertToSnapshot "
|
89
|
-
command << "#{conf_file_response.data} \"#{name}\" 2>&1"
|
90
|
-
|
91
|
-
Response.from_command(`#{command}`)
|
56
|
+
Fission::Action::Snapshot::Reverter.new(self).revert_to_snapshot(name)
|
92
57
|
end
|
93
58
|
|
94
59
|
# Public: List the snapshots for a VM.
|
@@ -103,27 +68,28 @@ module Fission
|
|
103
68
|
# snapshot names (String).
|
104
69
|
# If there is an error, an unsuccessful Response will be returned.
|
105
70
|
def snapshots
|
106
|
-
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
conf_file_response = conf_file
|
111
|
-
return conf_file_response unless conf_file_response.successful?
|
112
|
-
|
113
|
-
command = "#{vmrun_cmd} listSnapshots "
|
114
|
-
command << "#{conf_file_response.data} 2>&1"
|
115
|
-
output = `#{command}`
|
116
|
-
|
117
|
-
response = Response.new :code => $?.exitstatus
|
118
|
-
|
119
|
-
if response.successful?
|
120
|
-
snaps = output.split("\n").select { |s| !s.include? 'Total snapshots:' }
|
121
|
-
response.data = snaps.map { |s| s.strip }
|
122
|
-
else
|
123
|
-
response.message = output
|
124
|
-
end
|
71
|
+
Fission::Action::Snapshot::Lister.new(self).snapshots
|
72
|
+
end
|
125
73
|
|
126
|
-
|
74
|
+
# Public: Deletes a VM. The VM must not be running in order to delete it.
|
75
|
+
# As there are a number issues with the Fusion command line tool for
|
76
|
+
# deleting VMs, this is a best effort. The VM must not be running when this
|
77
|
+
# method is called. This essentially deletes the VM directory and attempts
|
78
|
+
# to remove the relevant entries from the Fusion plist file. It's highly
|
79
|
+
# recommended to delete VMs without the Fusion GUI running. If the Fusion
|
80
|
+
# GUI is running this method should succeed, but it's been observed that
|
81
|
+
# Fusion will recreate the plist data which is deleted. This leads to
|
82
|
+
# 'missing' VMs in the Fusion GUI.
|
83
|
+
#
|
84
|
+
# Examples
|
85
|
+
#
|
86
|
+
# @vm.delete
|
87
|
+
#
|
88
|
+
# Returns a Response with the result.
|
89
|
+
# If successful, the Response's data attribute will be nil.
|
90
|
+
# If there is an error, an unsuccessful Response will be returned.
|
91
|
+
def delete
|
92
|
+
Fission::Action::VM::Deleter.new(self).delete
|
127
93
|
end
|
128
94
|
|
129
95
|
# Public: Starts a VM. The VM must not be running in order to start it.
|
@@ -144,36 +110,7 @@ module Fission
|
|
144
110
|
# If successful, the Response's data attribute will be nil.
|
145
111
|
# If there is an error, an unsuccessful Response will be returned.
|
146
112
|
def start(options={})
|
147
|
-
|
148
|
-
return Response.new :code => 1, :message => 'VM does not exist'
|
149
|
-
end
|
150
|
-
|
151
|
-
running_response = running?
|
152
|
-
return running_response unless running_response.successful?
|
153
|
-
|
154
|
-
if running_response.data
|
155
|
-
return Response.new :code => 1, :message => 'VM is already running'
|
156
|
-
end
|
157
|
-
|
158
|
-
conf_file_response = conf_file
|
159
|
-
return conf_file_response unless conf_file_response.successful?
|
160
|
-
|
161
|
-
unless options[:headless].blank?
|
162
|
-
if Fusion.running?
|
163
|
-
message = 'It looks like the Fusion GUI is currently running. '
|
164
|
-
message << 'A VM cannot be started in headless mode when the Fusion GUI is running. '
|
165
|
-
message << 'Exit the Fusion GUI and try again.'
|
166
|
-
return Response.new :code => 1, :message => message
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
command = "#{vmrun_cmd} start "
|
171
|
-
command << "#{conf_file_response.data} "
|
172
|
-
|
173
|
-
command << (options[:headless].blank? ? 'gui ' : 'nogui ')
|
174
|
-
command << '2>&1'
|
175
|
-
|
176
|
-
Response.from_command(`#{command}`)
|
113
|
+
Fission::Action::VM::Starter.new(self).start(options)
|
177
114
|
end
|
178
115
|
|
179
116
|
# Public: Stops a VM. The VM must be running in order to stop it.
|
@@ -195,26 +132,7 @@ module Fission
|
|
195
132
|
# If successful, the Response's data attribute will be nil.
|
196
133
|
# If there is an error, an unsuccessful Response will be returned.
|
197
134
|
def stop(options={})
|
198
|
-
|
199
|
-
return Response.new :code => 1, :message => 'VM does not exist'
|
200
|
-
end
|
201
|
-
|
202
|
-
running_response = running?
|
203
|
-
return running_response unless running_response.successful?
|
204
|
-
|
205
|
-
unless running_response.data
|
206
|
-
return Response.new :code => 1, :message => 'VM is not running'
|
207
|
-
end
|
208
|
-
|
209
|
-
conf_file_response = conf_file
|
210
|
-
return conf_file_response unless conf_file_response.successful?
|
211
|
-
|
212
|
-
command = "#{vmrun_cmd} stop "
|
213
|
-
command << "#{conf_file_response.data} "
|
214
|
-
command << 'hard ' unless options[:hard].blank?
|
215
|
-
command << '2>&1'
|
216
|
-
|
217
|
-
Response.from_command(`#{command}`)
|
135
|
+
Fission::Action::VM::Stopper.new(self).stop(options)
|
218
136
|
end
|
219
137
|
|
220
138
|
# Public: Suspends a VM. The VM must be running in order to suspend it.
|
@@ -227,24 +145,35 @@ module Fission
|
|
227
145
|
# If successful, the Response's data attribute will be nil.
|
228
146
|
# If there is an error, an unsuccessful Response will be returned.
|
229
147
|
def suspend
|
230
|
-
|
231
|
-
|
232
|
-
end
|
148
|
+
Fission::Action::VM::Suspender.new(self).suspend
|
149
|
+
end
|
233
150
|
|
234
|
-
|
235
|
-
|
151
|
+
# Public: Provides virtual hardware info the VM
|
152
|
+
#
|
153
|
+
# Examples:
|
154
|
+
#
|
155
|
+
# @vm.hardware_info.data
|
156
|
+
# # => {'cpus' => 2, 'memory' => 1024}
|
157
|
+
#
|
158
|
+
# Returns a Response with the result.
|
159
|
+
# If successful, the Response's data attribute will be a Hash with the
|
160
|
+
# info found.
|
161
|
+
# If there is an error, an unsuccessful Response will be returned.
|
162
|
+
def hardware_info
|
163
|
+
config_response = conf_file_data
|
164
|
+
return config_response unless config_response.successful?
|
236
165
|
|
237
|
-
|
238
|
-
return Response.new :code => 1, :message => 'VM is not running'
|
239
|
-
end
|
166
|
+
response = Response.new :code => 0, :data => {}
|
240
167
|
|
241
|
-
|
242
|
-
return conf_file_response unless conf_file_response.successful?
|
168
|
+
response.data['cpus'] = 1
|
243
169
|
|
244
|
-
|
245
|
-
|
170
|
+
{ 'cpus' => 'numvcpus', 'memory' => 'memsize' }.each_pair do |k,v|
|
171
|
+
unless config_response.data[v].blank?
|
172
|
+
response.data[k] = config_response.data[v].to_i
|
173
|
+
end
|
174
|
+
end
|
246
175
|
|
247
|
-
|
176
|
+
response
|
248
177
|
end
|
249
178
|
|
250
179
|
# Public: Provides the MAC addresses for a VM.
|
@@ -297,30 +226,76 @@ module Fission
|
|
297
226
|
# attribute will be an empty Hash.
|
298
227
|
# If there is an error, an unsuccessful Response will be returned.
|
299
228
|
def network_info
|
300
|
-
|
301
|
-
return
|
229
|
+
config_response = conf_file_data
|
230
|
+
return config_response unless config_response.successful?
|
302
231
|
|
303
232
|
response = Response.new :code => 0, :data => {}
|
304
233
|
|
305
234
|
interface_pattern = /^ethernet\d+/
|
306
235
|
mac_pattern = /(\w\w[:-]\w\w[:-]\w\w[:-]\w\w[:-]\w\w[:-]\w\w)/
|
307
236
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
response.data[int] = {}
|
313
|
-
response.data[int]['mac_address'] = mac
|
314
|
-
|
237
|
+
config_response.data.each_pair do |k,v|
|
238
|
+
if v =~ mac_pattern
|
239
|
+
mac = v
|
240
|
+
int = k.scan(interface_pattern).first
|
241
|
+
response.data[int] = { 'mac_address' => mac }
|
315
242
|
lease_response = Fission::Lease.find_by_mac_address mac
|
316
243
|
return lease_response unless lease_response.successful?
|
317
244
|
|
318
245
|
response.data[int]['ip_address'] = nil
|
319
|
-
|
320
246
|
if lease_response.data
|
321
247
|
response.data[int]['ip_address'] = lease_response.data.ip_address
|
322
248
|
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
response
|
253
|
+
end
|
254
|
+
|
255
|
+
# Public: Provides the Fussion GuestOS profile.
|
256
|
+
#
|
257
|
+
# Examples
|
258
|
+
#
|
259
|
+
# @vm.guestos.data
|
260
|
+
# # => 'debian5'
|
261
|
+
#
|
262
|
+
# Returns a Response with the result.
|
263
|
+
# If the Response is successful, the Response's data attribute will
|
264
|
+
# be populated with a string that is the guest operatingsystem used for the
|
265
|
+
# virtual machine.
|
266
|
+
# If there is an error, an unsuccessful Response will be returned.
|
267
|
+
def guestos
|
268
|
+
config_response = conf_file_data
|
269
|
+
return config_response unless config_response.successful?
|
323
270
|
|
271
|
+
response = Response.new :code => 0, :data => {}
|
272
|
+
response.data = config_response.data.fetch 'guestOS', ''
|
273
|
+
response
|
274
|
+
end
|
275
|
+
|
276
|
+
# Public: Provides various uuids associated with a VM.
|
277
|
+
#
|
278
|
+
# Examples
|
279
|
+
#
|
280
|
+
# @vm.uuids.data
|
281
|
+
# # => {"bios"=>"56 4d ee 72 3b 7e 47 67-69 aa 65 cb 5e 40 3f 21",
|
282
|
+
# "location"=>"56 4d 2e 15 f4 ed 00 a7-c5 99 43 32 b8 76 ef d5"}
|
283
|
+
#
|
284
|
+
# Returns a Response with the result.
|
285
|
+
# If the Response is successful, the Response's data attribute will
|
286
|
+
# be populated with a hash that is comprised of the various uuids that are
|
287
|
+
# associated with each VM. If the VM is newly created they will be the same
|
288
|
+
# but if you selected 'I Moved It' from the Fusion GUI they will differ.
|
289
|
+
# If there is an error, an unsuccessful Response will be returned.
|
290
|
+
def uuids
|
291
|
+
config_response = conf_file_data
|
292
|
+
return config_response unless config_response.successful?
|
293
|
+
|
294
|
+
response = Response.new :code => 0, :data => {}
|
295
|
+
|
296
|
+
{ 'bios' => 'uuid.bios', 'location' => 'uuid.location' }.each_pair do |k,v|
|
297
|
+
unless config_response.data[v].blank?
|
298
|
+
response.data[k] = config_response.data[v]
|
324
299
|
end
|
325
300
|
end
|
326
301
|
|
@@ -439,6 +414,22 @@ module Fission
|
|
439
414
|
response
|
440
415
|
end
|
441
416
|
|
417
|
+
# Public: Provides the configuration data stored in the VM's configuration
|
418
|
+
# file ('.vmx').
|
419
|
+
#
|
420
|
+
# Examples
|
421
|
+
#
|
422
|
+
# @vm.conf_file_data
|
423
|
+
#
|
424
|
+
# Returns a Response with the result.
|
425
|
+
# If successful, the Response's data attribute with be a Hash of the
|
426
|
+
# configuration data. All of the keys/values in the configuration data will
|
427
|
+
# be a String.
|
428
|
+
# If there is an error, an unsuccessful Response will be returned.
|
429
|
+
def conf_file_data
|
430
|
+
VMConfiguration.new(self).config_data
|
431
|
+
end
|
432
|
+
|
442
433
|
# Public: Determines the path to the VM's config file ('.vmx').
|
443
434
|
#
|
444
435
|
# Examples
|
@@ -485,8 +476,6 @@ module Fission
|
|
485
476
|
end
|
486
477
|
end
|
487
478
|
|
488
|
-
response.data.gsub! ' ', '\ ' if response.successful?
|
489
|
-
|
490
479
|
response
|
491
480
|
end
|
492
481
|
|
@@ -519,14 +508,7 @@ module Fission
|
|
519
508
|
# empty Array.
|
520
509
|
# If there is an error, an unsuccessful Response will be returned.
|
521
510
|
def self.all
|
522
|
-
|
523
|
-
File.directory? d
|
524
|
-
end
|
525
|
-
|
526
|
-
response = Response.new :code => 0
|
527
|
-
response.data = vm_dirs.collect { |d| new(File.basename d, '.vmwarevm') }
|
528
|
-
|
529
|
-
response
|
511
|
+
Fission::Action::VM::Lister.new.all
|
530
512
|
end
|
531
513
|
|
532
514
|
# Public: Provides all of the VMs which are currently running.
|
@@ -543,25 +525,7 @@ module Fission
|
|
543
525
|
# attribute will be an empty Array.
|
544
526
|
# If there is an error, an unsuccessful Response will be returned.
|
545
527
|
def self.all_running
|
546
|
-
|
547
|
-
|
548
|
-
output = `#{command}`
|
549
|
-
|
550
|
-
response = Response.new :code => $?.exitstatus
|
551
|
-
|
552
|
-
if response.successful?
|
553
|
-
vms = output.split("\n").select do |vm|
|
554
|
-
vm.include?('.vmx') && File.exists?(vm) && File.extname(vm) == '.vmx'
|
555
|
-
end
|
556
|
-
|
557
|
-
response.data = vms.collect do |vm|
|
558
|
-
new File.basename(File.dirname(vm), '.vmwarevm')
|
559
|
-
end
|
560
|
-
else
|
561
|
-
response.message = output
|
562
|
-
end
|
563
|
-
|
564
|
-
response
|
528
|
+
Fission::Action::VM::Lister.new.all_running
|
565
529
|
end
|
566
530
|
|
567
531
|
# Public: Provides a list of all of the VMs and their associated status
|
@@ -576,34 +540,7 @@ module Fission
|
|
576
540
|
# names as keys and their status as the values.
|
577
541
|
# If there is an error, an unsuccessful Repsonse will be returned.
|
578
542
|
def self.all_with_status
|
579
|
-
|
580
|
-
return all_response unless all_response.successful?
|
581
|
-
|
582
|
-
all_vms = all_response.data
|
583
|
-
|
584
|
-
running_response = all_running
|
585
|
-
return running_response unless running_response.successful?
|
586
|
-
|
587
|
-
response = Response.new :code => 0
|
588
|
-
|
589
|
-
all_running_vm_names = running_response.data.collect { |v| v.name }
|
590
|
-
|
591
|
-
response.data = all_vms.inject({}) do |result, vm|
|
592
|
-
if all_running_vm_names.include? vm.name
|
593
|
-
status = 'running'
|
594
|
-
else
|
595
|
-
if vm.suspend_file_exists?
|
596
|
-
status = 'suspended'
|
597
|
-
else
|
598
|
-
status = 'not running'
|
599
|
-
end
|
600
|
-
end
|
601
|
-
|
602
|
-
result[vm.name] = status
|
603
|
-
result
|
604
|
-
end
|
605
|
-
|
606
|
-
response
|
543
|
+
Fission::Action::VM::Lister.new.all_with_status
|
607
544
|
end
|
608
545
|
|
609
546
|
# Public: Creates a new VM which is a clone of an existing VM. As Fusion
|
@@ -622,189 +559,12 @@ module Fission
|
|
622
559
|
# If successful, the Response's data attribute will be nil.
|
623
560
|
# If there is an error, an unsuccessful Response will be returned.
|
624
561
|
def self.clone(source_vm_name, target_vm_name)
|
625
|
-
source_vm = new source_vm_name
|
626
|
-
target_vm = new target_vm_name
|
627
|
-
|
628
|
-
unless source_vm.exists?
|
629
|
-
return Response.new :code => 1, :message => 'VM does not exist'
|
630
|
-
end
|
631
|
-
|
632
|
-
if target_vm.exists?
|
633
|
-
return Response.new :code => 1, :message => 'VM already exists'
|
634
|
-
end
|
635
|
-
|
636
|
-
FileUtils.cp_r source_vm.path, target_vm.path
|
637
|
-
|
638
|
-
rename_vm_files source_vm.name, target_vm.name
|
639
|
-
update_config source_vm.name, target_vm.name
|
640
|
-
|
641
|
-
Response.new :code => 0
|
642
|
-
end
|
643
|
-
|
644
|
-
# Public: Deletes a VM. The VM must not be running in order to delete it.
|
645
|
-
# As there are a number issues with the Fusion command line tool for
|
646
|
-
# deleting VMs, this is a best effort. The VM must not be running when this
|
647
|
-
# method is called. This essentially deletes the VM directory and attempts
|
648
|
-
# to remove the relevant entries from the Fusion plist file. It's highly
|
649
|
-
# recommended to delete VMs without the Fusion GUI running. If the Fusion
|
650
|
-
# GUI is running this method should succeed, but it's been observed that
|
651
|
-
# Fusion will recreate the plist data which is deleted. This leads to
|
652
|
-
# 'missing' VMs in the Fusion GUI.
|
653
|
-
#
|
654
|
-
# Examples
|
655
|
-
#
|
656
|
-
# @vm.delete
|
657
|
-
#
|
658
|
-
# Returns a Response with the result.
|
659
|
-
# If successful, the Response's data attribute will be nil.
|
660
|
-
# If there is an error, an unsuccessful Response will be returned.
|
661
|
-
def delete
|
662
|
-
unless exists?
|
663
|
-
return Response.new :code => 1, :message => 'VM does not exist'
|
664
|
-
end
|
665
|
-
|
666
|
-
running_response = running?
|
667
|
-
return running_response unless running_response.successful?
|
668
|
-
|
669
|
-
if running_response.data
|
670
|
-
message = 'The VM must not be running in order to delete it.'
|
671
|
-
return Response.new :code => 1, :message => message
|
672
|
-
end
|
673
|
-
|
674
|
-
FileUtils.rm_rf path
|
675
|
-
Metadata.delete_vm_info path
|
676
|
-
|
677
|
-
Response.new :code => 0
|
562
|
+
@source_vm = new source_vm_name
|
563
|
+
@target_vm = new target_vm_name
|
564
|
+
Fission::Action::VM::Cloner.new(@source_vm, @target_vm).clone
|
678
565
|
end
|
679
566
|
|
680
567
|
private
|
681
|
-
# Internal: Renames the files of a newly cloned VM.
|
682
|
-
#
|
683
|
-
# from - The VM name that was used as the source of the clone.
|
684
|
-
# to - The name of the newly cloned VM.
|
685
|
-
#
|
686
|
-
# Examples
|
687
|
-
#
|
688
|
-
# Fission::VM.rename_vm_files 'foo', 'bar'
|
689
|
-
#
|
690
|
-
# Returns nothing.
|
691
|
-
def self.rename_vm_files(from, to)
|
692
|
-
to_vm = new to
|
693
|
-
|
694
|
-
files_to_rename(from, to).each do |file|
|
695
|
-
text_to_replace = File.basename(file, File.extname(file))
|
696
|
-
|
697
|
-
if File.extname(file) == '.vmdk'
|
698
|
-
if file.match /\-s\d+\.vmdk/
|
699
|
-
text_to_replace = file.partition(/\-s\d+.vmdk/).first
|
700
|
-
end
|
701
|
-
end
|
702
|
-
|
703
|
-
unless File.exists?(File.join(to_vm.path, file.gsub(text_to_replace, to)))
|
704
|
-
FileUtils.mv File.join(to_vm.path, file),
|
705
|
-
File.join(to_vm.path, file.gsub(text_to_replace, to))
|
706
|
-
end
|
707
|
-
end
|
708
|
-
end
|
709
|
-
|
710
|
-
# Internal: Provides the list of files which need to be renamed in a newly
|
711
|
-
# cloned VM directory.
|
712
|
-
#
|
713
|
-
# from - The VM name that was used as the source of the clone.
|
714
|
-
# to - The name of the newly cloned VM.
|
715
|
-
#
|
716
|
-
# Examples
|
717
|
-
#
|
718
|
-
# Fission::VM.files_to_rename 'foo', 'bar'
|
719
|
-
# # => ['/vms/vm1/foo.vmdk', '/vms/vm1/foo.vmx', 'vms/vm1/blah.other']
|
720
|
-
#
|
721
|
-
# Returns an Array containing the paths (String) to the files to rename.
|
722
|
-
# The paths which match the from name will preceed any other files found in
|
723
|
-
# the newly cloned VM directory.
|
724
|
-
def self.files_to_rename(from, to)
|
725
|
-
to_vm = new to
|
726
|
-
|
727
|
-
files_which_match_source_vm = []
|
728
|
-
other_files = []
|
729
|
-
|
730
|
-
Dir.entries(to_vm.path).each do |f|
|
731
|
-
unless f == '.' || f == '..'
|
732
|
-
f.include?(from) ? files_which_match_source_vm << f : other_files << f
|
733
|
-
end
|
734
|
-
end
|
735
|
-
|
736
|
-
files_which_match_source_vm + other_files
|
737
|
-
end
|
738
|
-
|
739
|
-
# Internal: Provides the list of file extensions for VM related files.
|
740
|
-
#
|
741
|
-
# Examples
|
742
|
-
#
|
743
|
-
# Fission::VM.vm_file_extension
|
744
|
-
# # => ['.nvram', '.vmdk', '.vmem']
|
745
|
-
#
|
746
|
-
# Returns an Array containing the file extensions of VM realted files.
|
747
|
-
# The file extensions returned are Strings and include a '.'.
|
748
|
-
def self.vm_file_extensions
|
749
|
-
['.nvram', '.vmdk', '.vmem', '.vmsd', '.vmss', '.vmx', '.vmxf']
|
750
|
-
end
|
751
|
-
|
752
|
-
# Internal: Updates config files for a newly cloned VM. This will update any
|
753
|
-
# files with the extension of '.vmx', '.vmxf', and '.vmdk'. Any binary
|
754
|
-
# '.vmdk' files will be skipped.
|
755
|
-
#
|
756
|
-
# from - The VM name that was used as the source of the clone.
|
757
|
-
# to - The name of the newly cloned VM.
|
758
|
-
#
|
759
|
-
# Examples
|
760
|
-
#
|
761
|
-
# Fission::VM.update_config 'foo', 'bar'
|
762
|
-
#
|
763
|
-
# Returns nothing.
|
764
|
-
def self.update_config(from, to)
|
765
|
-
to_vm = new to
|
766
|
-
|
767
|
-
['.vmx', '.vmxf', '.vmdk'].each do |ext|
|
768
|
-
file = File.join to_vm.path, "#{to}#{ext}"
|
769
|
-
|
770
|
-
unless File.binary?(file)
|
771
|
-
text = (File.read file).gsub from, to
|
772
|
-
File.open(file, 'w'){ |f| f.print text }
|
773
|
-
end
|
774
|
-
|
775
|
-
clean_up_conf_file(file) if ext == '.vmx'
|
776
|
-
end
|
777
|
-
end
|
778
|
-
|
779
|
-
# Internal: Cleans up the conf file (*.vmx) for a newly cloned VM. This
|
780
|
-
# includes removing generated MAC addresses, setting up for a new UUID, and
|
781
|
-
# disable VMware tools warning.
|
782
|
-
#
|
783
|
-
# conf_file_path - Aboslute path to the VM's conf file (.vmx).
|
784
|
-
#
|
785
|
-
# Examples
|
786
|
-
#
|
787
|
-
# VM.clean_up_conf_file '/vms/foo/foo.vmx'
|
788
|
-
#
|
789
|
-
# Returns nothing.
|
790
|
-
def self.clean_up_conf_file(conf_file_path)
|
791
|
-
conf_items_patterns = [ /^tools\.remindInstall.*\n/,
|
792
|
-
/^uuid\.action.*\n/,
|
793
|
-
/^ethernet\.+generatedAddress.*\n/ ]
|
794
|
-
|
795
|
-
content = File.read conf_file_path
|
796
|
-
|
797
|
-
conf_items_patterns.each do |pattern|
|
798
|
-
content.gsub(pattern, '').strip
|
799
|
-
end
|
800
|
-
|
801
|
-
content << "\n"
|
802
|
-
content << "tools.remindInstall = \"FALSE\"\n"
|
803
|
-
content << "uuid.action = \"create\"\n"
|
804
|
-
|
805
|
-
File.open(conf_file_path, 'w') { |f| f.print content }
|
806
|
-
end
|
807
|
-
|
808
568
|
# Internal: Helper for getting the configured vmrun_cmd value.
|
809
569
|
#
|
810
570
|
# Examples
|