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.
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