fission 0.4.0 → 0.5.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.ruby-gemset +1 -0
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +12 -3
  5. data/README.md +45 -19
  6. data/bin/fission +1 -1
  7. data/fission.gemspec +3 -2
  8. data/lib/fission.rb +15 -0
  9. data/lib/fission/action/shell_executor.rb +37 -0
  10. data/lib/fission/action/snapshot/creator.rb +81 -0
  11. data/lib/fission/action/snapshot/deleter.rb +85 -0
  12. data/lib/fission/action/snapshot/lister.rb +90 -0
  13. data/lib/fission/action/snapshot/reverter.rb +81 -0
  14. data/lib/fission/action/vm/cloner.rb +191 -0
  15. data/lib/fission/action/vm/deleter.rb +73 -0
  16. data/lib/fission/action/vm/lister.rb +138 -0
  17. data/lib/fission/action/vm/starter.rb +88 -0
  18. data/lib/fission/action/vm/stopper.rb +79 -0
  19. data/lib/fission/action/vm/suspender.rb +68 -0
  20. data/lib/fission/cli.rb +21 -117
  21. data/lib/fission/command.rb +39 -0
  22. data/lib/fission/command/clone.rb +11 -6
  23. data/lib/fission/command/delete.rb +11 -6
  24. data/lib/fission/command/info.rb +62 -0
  25. data/lib/fission/command/snapshot_create.rb +9 -3
  26. data/lib/fission/command/snapshot_delete.rb +38 -0
  27. data/lib/fission/command/snapshot_list.rb +9 -3
  28. data/lib/fission/command/snapshot_revert.rb +9 -3
  29. data/lib/fission/command/start.rb +11 -6
  30. data/lib/fission/command/status.rb +9 -1
  31. data/lib/fission/command/stop.rb +9 -3
  32. data/lib/fission/command/suspend.rb +11 -6
  33. data/lib/fission/command_helpers.rb +18 -4
  34. data/lib/fission/command_line_parser.rb +189 -0
  35. data/lib/fission/config.rb +1 -1
  36. data/lib/fission/fusion.rb +3 -4
  37. data/lib/fission/lease.rb +2 -1
  38. data/lib/fission/metadata.rb +6 -1
  39. data/lib/fission/response.rb +17 -9
  40. data/lib/fission/version.rb +1 -1
  41. data/lib/fission/vm.rb +142 -382
  42. data/lib/fission/vm_configuration.rb +79 -0
  43. data/spec/fission/action/execute_shell_command_spec.rb +25 -0
  44. data/spec/fission/action/snapshot/creator_spec.rb +77 -0
  45. data/spec/fission/action/snapshot/deleter_spec.rb +84 -0
  46. data/spec/fission/action/snapshot/lister_spec.rb +67 -0
  47. data/spec/fission/action/snapshot/reverter_spec.rb +76 -0
  48. data/spec/fission/action/vm/cloner_spec.rb +198 -0
  49. data/spec/fission/action/vm/deleter_spec.rb +79 -0
  50. data/spec/fission/action/vm/lister_spec.rb +164 -0
  51. data/spec/fission/action/vm/starter_spec.rb +88 -0
  52. data/spec/fission/action/vm/stopper_spec.rb +71 -0
  53. data/spec/fission/action/vm/suspender_spec.rb +59 -0
  54. data/spec/fission/cli_spec.rb +32 -157
  55. data/spec/fission/command/clone_spec.rb +9 -3
  56. data/spec/fission/command/delete_spec.rb +11 -3
  57. data/spec/fission/command/info_spec.rb +130 -0
  58. data/spec/fission/command/snapshot_create_spec.rb +11 -3
  59. data/spec/fission/command/snapshot_delete_spec.rb +74 -0
  60. data/spec/fission/command/snapshot_list_spec.rb +11 -3
  61. data/spec/fission/command/snapshot_revert_spec.rb +11 -3
  62. data/spec/fission/command/start_spec.rb +11 -3
  63. data/spec/fission/command/status_spec.rb +16 -5
  64. data/spec/fission/command/stop_spec.rb +11 -3
  65. data/spec/fission/command/suspend_spec.rb +11 -3
  66. data/spec/fission/command_helpers_spec.rb +27 -5
  67. data/spec/fission/command_line_parser_spec.rb +267 -0
  68. data/spec/fission/command_spec.rb +16 -1
  69. data/spec/fission/config_spec.rb +3 -3
  70. data/spec/fission/fusion_spec.rb +11 -6
  71. data/spec/fission/lease_spec.rb +81 -45
  72. data/spec/fission/metadata_spec.rb +29 -6
  73. data/spec/fission/response_spec.rb +20 -9
  74. data/spec/fission/ui_spec.rb +1 -1
  75. data/spec/fission/vm_configuration_spec.rb +132 -0
  76. data/spec/fission/vm_spec.rb +393 -750
  77. data/spec/helpers/command_helpers.rb +1 -1
  78. metadata +93 -15
  79. data/.rvmrc +0 -1
@@ -0,0 +1,88 @@
1
+ module Fission
2
+ module Action
3
+ module VM
4
+
5
+ class Starter
6
+
7
+ # Internal: Creates a new VMStarter object. This accepts a VM object.
8
+ #
9
+ # vm - An instance of VM
10
+ #
11
+ # Examples:
12
+ #
13
+ # Fission::Action::VMStarter.new @my_vm
14
+ #
15
+ # Returns a new VMStarter object
16
+ def initialize(vm)
17
+ @vm = vm
18
+ end
19
+
20
+ # Public: Starts a VM. The VM must not be running in order to start it.
21
+ #
22
+ # options - Hash of options:
23
+ # :headless - Boolean which specifies to start the VM without
24
+ # a GUI console. The Fusion GUI must not be
25
+ # running in order to start the VM headless.
26
+ # (default: false)
27
+ #
28
+ # Examples
29
+ #
30
+ # @vm_starter.start
31
+ #
32
+ # @vm_starter.start :headless => true
33
+ #
34
+ # Returns a Response with the result.
35
+ # If successful, the Response's data attribute will be nil.
36
+ # If there is an error, an unsuccessful Response will be returned.
37
+ def start(options={})
38
+ unless @vm.exists?
39
+ return Response.new :code => 1, :message => 'VM does not exist'
40
+ end
41
+
42
+ running_response = @vm.running?
43
+ return running_response unless running_response.successful?
44
+
45
+ if running_response.data
46
+ return Response.new :code => 1, :message => 'VM is already running'
47
+ end
48
+
49
+ conf_file_response = @vm.conf_file
50
+ return conf_file_response unless conf_file_response.successful?
51
+
52
+ unless options[:headless].blank?
53
+ if Fusion.running?
54
+ message = 'It looks like the Fusion GUI is currently running. '
55
+ message << 'A VM cannot be started in headless mode when the Fusion GUI is running. '
56
+ message << 'Exit the Fusion GUI and try again.'
57
+ return Response.new :code => 1, :message => message
58
+ end
59
+ end
60
+
61
+ command = "#{vmrun_cmd} start "
62
+ command << "'#{conf_file_response.data}' "
63
+
64
+ command << (options[:headless].blank? ? 'gui ' : 'nogui ')
65
+ command << '2>&1'
66
+
67
+ command_exec = Fission::Action::ShellExecutor.new command
68
+ Response.from_shell_executor command_exec.execute
69
+ end
70
+
71
+ private
72
+ # Internal: Helper for getting the configured vmrun_cmd value.
73
+ #
74
+ # Examples
75
+ #
76
+ # @vm_starter.vmrun_cmd
77
+ # # => "/foo/bar/vmrun -T fusion"
78
+ #
79
+ # Returns a String for the configured value of
80
+ # Fission.config['vmrun_cmd'].
81
+ def vmrun_cmd
82
+ Fission.config['vmrun_cmd']
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,79 @@
1
+ module Fission
2
+ module Action
3
+ module VM
4
+
5
+ class Stopper
6
+
7
+ # Internal: Creates a new VMStopper object. This accepts a VM object.
8
+ #
9
+ # vm - An instance of VM
10
+ #
11
+ # Examples:
12
+ #
13
+ # Fission::Action::VMStopper.new @my_vm
14
+ #
15
+ # Returns a new VMStopper object
16
+ def initialize(vm)
17
+ @vm = vm
18
+ end
19
+
20
+ # Public: Stops a VM. The VM must be running in order to stop it.
21
+ #
22
+ # options - Hash of options:
23
+ # :hard - Boolean which specifies to power off the VM (instead
24
+ # of attempting to initiate a graceful shutdown). This
25
+ # is the equivalent of passing 'hard' to the vmrun
26
+ # stop command.
27
+ # (default: false)
28
+ #
29
+ # Examples
30
+ #
31
+ # @stopper.stop
32
+ #
33
+ # @stopper.stop :hard => true
34
+ #
35
+ # Returns a Response with the result.
36
+ # If successful, the Response's data attribute will be nil.
37
+ # If there is an error, an unsuccessful Response will be returned.
38
+ def stop(options={})
39
+ unless @vm.exists?
40
+ return Response.new :code => 1, :message => 'VM does not exist'
41
+ end
42
+
43
+ running_response = @vm.running?
44
+ return running_response unless running_response.successful?
45
+
46
+ unless running_response.data
47
+ return Response.new :code => 1, :message => 'VM is not running'
48
+ end
49
+
50
+ conf_file_response = @vm.conf_file
51
+ return conf_file_response unless conf_file_response.successful?
52
+
53
+ command = "#{vmrun_cmd} stop "
54
+ command << "'#{conf_file_response.data}' "
55
+ command << 'hard ' unless options[:hard].blank?
56
+ command << '2>&1'
57
+
58
+ command_exec = Fission::Action::ShellExecutor.new command
59
+ Response.from_shell_executor command_exec.execute
60
+ end
61
+
62
+ private
63
+ # Internal: Helper for getting the configured vmrun_cmd value.
64
+ #
65
+ # Examples
66
+ #
67
+ # @vm_stopper.vmrun_cmd
68
+ # # => "/foo/bar/vmrun -T fusion"
69
+ #
70
+ # Returns a String for the configured value of
71
+ # Fission.config['vmrun_cmd'].
72
+ def vmrun_cmd
73
+ Fission.config['vmrun_cmd']
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,68 @@
1
+ module Fission
2
+ module Action
3
+ module VM
4
+
5
+ class Suspender
6
+
7
+ # Internal: Creates a new VMSuspender object. This accepts a VM object.
8
+ #
9
+ # vm - An instance of VM
10
+ #
11
+ # Examples:
12
+ #
13
+ # Fission::Action::VMSuspender.new @my_vm
14
+ #
15
+ # Returns a new VMSuspender object
16
+ def initialize(vm)
17
+ @vm = vm
18
+ end
19
+
20
+ # Public: Suspends a VM. The VM must be running in order to suspend it.
21
+ #
22
+ # Examples
23
+ #
24
+ # @suspender.suspend
25
+ #
26
+ # Returns a Response with the result.
27
+ # If successful, the Response's data attribute will be nil.
28
+ # If there is an error, an unsuccessful Response will be returned.
29
+ def suspend
30
+ unless @vm.exists?
31
+ return Response.new :code => 1, :message => 'VM does not exist'
32
+ end
33
+
34
+ running_response = @vm.running?
35
+ return running_response unless running_response.successful?
36
+
37
+ unless running_response.data
38
+ return Response.new :code => 1, :message => 'VM is not running'
39
+ end
40
+
41
+ conf_file_response = @vm.conf_file
42
+ return conf_file_response unless conf_file_response.successful?
43
+
44
+ command = "#{vmrun_cmd} suspend "
45
+ command << "'#{conf_file_response.data}' 2>&1"
46
+
47
+ command_exec = Fission::Action::ShellExecutor.new command
48
+ Response.from_shell_executor command_exec.execute
49
+ end
50
+
51
+ private
52
+ # Internal: Helper for getting the configured vmrun_cmd value.
53
+ #
54
+ # Examples
55
+ #
56
+ # @suspender.vmrun_cmd
57
+ # # => "/foo/bar/vmrun -T fusion"
58
+ #
59
+ # Returns a String for the configured value of
60
+ # Fission.config['vmrun_cmd'].
61
+ def vmrun_cmd
62
+ Fission.config['vmrun_cmd']
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -1,141 +1,45 @@
1
1
  module Fission
2
2
  class CLI
3
3
 
4
- # Internal: Starts the command line parsing logic and hands off to the
5
- # requested commands. If there are invalid arguments or errors then the
6
- # help text will be displayed.
7
- #
8
- # args - The list of arguments for the Fission command line app. This
9
- # should be the raw command line arguments.
4
+ # Internal: Creates a new Fission::CLI object. This automatically parses
5
+ # the arguments in ARGV. This will also automatically display the usage
6
+ # and exit if applicable.
10
7
  #
11
8
  # Examples
12
9
  #
13
- # Fission::CLI.execute
10
+ # Fission::CLI.new
14
11
  #
15
- # Returns nothing.
16
- def self.execute(args=ARGV)
17
- optparse = OptionParser.new do |opts|
18
- opts.banner = "\nUsage: fission [options] COMMAND [arguments]"
19
-
20
- opts.on_head('-v', '--version', 'Output the version of fission') do
21
- ui.output VERSION
22
- exit(0)
23
- end
24
-
25
- opts.on_head('-h', '--help', 'Displays this message') do
26
- show_all_help(optparse)
27
- exit(0)
28
- end
29
-
30
- opts.define_tail do
31
- commands_banner
32
- end
12
+ # Returns a Fission::CLI object.
13
+ def initialize(args=ARGV, parser=CommandLineParser)
14
+ @args = args ||= ARGV
33
15
 
34
- end
16
+ @parser = parser.new @args
35
17
 
36
- begin
37
- optparse.order! args
38
- rescue OptionParser::InvalidOption => e
39
- ui.output e
40
- show_all_help(optparse)
41
- exit(1)
42
- end
43
-
44
- if commands.include?(args.first)
45
- @cmd = Command.const_get(args.first.capitalize).new args.drop 1
46
- elsif is_snapshot_command?(args)
47
- klass = args.take(2).map {|c| c.capitalize}.join('')
48
- @cmd = Command.const_get(klass).new args.drop 2
49
- else
50
- show_all_help(optparse)
51
- exit(1)
52
- end
53
-
54
- @cmd.execute
18
+ parse_arguments
55
19
  end
56
20
 
57
- # Internal: Provides the list of Fission commands based on the files in the
58
- # command directory.
21
+ # Internal: Execute the determined command.
59
22
  #
60
- # Examples
23
+ # Examples:
61
24
  #
62
- # Fission::CLI.commands
63
- # # => ['clone', 'delete', 'snapshot create', 'snapshot list']
25
+ # Fission::CLI.new(ARGV).execute
64
26
  #
65
- # Returns an Array of the commands (String). Commands with underscores will
66
- # have them replaced with spaces.
67
- def self.commands
68
- cmds = Dir.entries(File.join(File.dirname(__FILE__), 'command')).select do |file|
69
- !File.directory? file
70
- end
71
-
72
- cmds.map { |cmd| File.basename(cmd, '.rb').gsub '_', ' ' }
27
+ # Returns nothing.
28
+ def execute
29
+ @cmd.execute
73
30
  end
74
31
 
75
32
  private
76
- # Internal: Determines if the provided command is a snapshot related
77
- # command.
33
+ # Internal: Parses the arguments using the parser.
78
34
  #
79
- # args - The arguments (Array) to interrogate. This should be the command
80
- # line arguments. Only the first two items in the Array will be
81
- # used.
82
- #
83
- # Examples
35
+ # Examples:
84
36
  #
85
- # Fission::CLI.is_snapshot_command? ['foo', 'bar']
86
- # # => false
87
- #
88
- # Fission::CLI.is_snapshot_command? ['snapshot', 'list']
89
- # # => true
90
- #
91
- # Returns a Boolean of whether a snapshot command was given or not.
92
- def self.is_snapshot_command?(args)
93
- args.first == 'snapshot' && args.count > 1 && commands.include?(args.take(2).join(' '))
94
- end
95
-
96
- # Internal: Provides the help of all of the known commands.
97
- #
98
- # Examples
99
- #
100
- # Fission::CLI.commands_banner
101
- #
102
- # Returns a String which is a concatenation of the help text for all known
103
- # commands.
104
- def self.commands_banner
105
- text = "\nCommands:\n"
106
- Command.descendants.each do |command_klass|
107
- text << (command_klass.send :help)
108
- end
109
-
110
- text
111
- end
112
-
113
- # Internal: Helper method to output the command line options and the help
114
- # for all known commands to the terminal.
115
- #
116
- # options - The options to display as a part of the output. This can (and
117
- # in almost all cases) should be the optparse object.
118
- #
119
- # Examples
120
- #
121
- # Fission::CLI.show_all_help my_opt_parse
122
- # # => 'fission options command arguments ....' (concatenated)
37
+ # @cli.parse_arguments
123
38
  #
124
39
  # Returns nothing.
125
- def self.show_all_help(options)
126
- ui.output options
127
- ui.output commands_banner
128
- end
129
-
130
- # Internal: Helper method for outputting text to the ui
131
- #
132
- # Examples
133
- #
134
- # CLI.ui.output 'foo'
135
- #
136
- # Returns a UI instance.
137
- def self.ui
138
- @ui ||= UI.new
40
+ def parse_arguments
41
+ @parser.parse
42
+ @cmd = @parser.command
139
43
  end
140
44
 
141
45
  end
@@ -1,7 +1,9 @@
1
1
  require 'forwardable'
2
+ require 'fission/command_helpers'
2
3
 
3
4
  module Fission
4
5
  class Command
6
+ include Fission::CommandHelpers
5
7
  extend Forwardable
6
8
 
7
9
  def_delegators :@ui, :output, :output_and_exit, :output_printf
@@ -28,6 +30,17 @@ module Fission
28
30
  @args = args
29
31
  end
30
32
 
33
+ # Internal: Primary method for performing an action within a command.
34
+ #
35
+ # Examples
36
+ #
37
+ # command.execute
38
+ #
39
+ # Returns nothing
40
+ def execute
41
+ parse_arguments
42
+ end
43
+
31
44
  # Internal: Helper method used to delegate UI related methods through.
32
45
  #
33
46
  # Examples
@@ -39,6 +52,32 @@ module Fission
39
52
  @ui ||= UI.new
40
53
  end
41
54
 
55
+ # Internal: Helper method to determine the command name of command class.
56
+ # This should only be called against descendants of this class.
57
+ #
58
+ # #xamples:
59
+ # Fission::Command::SnapshotList.new.command_name
60
+ # # => 'snapshot list'
61
+ #
62
+ # Returns the command name as a String.
63
+ def command_name(klass=self)
64
+ klass.class.name.split('::')[2].
65
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
66
+ gsub('_', ' ').downcase
67
+ end
68
+
69
+ # Internal: Summmary of the command. This is to be implemented by any
70
+ # class which inherits from this class.
71
+ #
72
+ # Examples
73
+ # command.summary
74
+ # # => 'This command does x and y'
75
+ #
76
+ # Returns a String summary of the command.
77
+ def summary
78
+ raise NotImplementedError
79
+ end
80
+
42
81
  # Internal: Helper method to return the help text of a command. This is
43
82
  # intended to be used by a command class which inherits from this class.
44
83
  # This method will call the 'option_parser' method which must be defined in