rhc 0.94.8 → 0.95.13

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 (59) hide show
  1. data/README.md +27 -1
  2. data/bin/rhc +15 -23
  3. data/bin/rhc-app +4 -1
  4. data/bin/rhc-chk +3 -0
  5. data/bin/rhc-create-app +3 -0
  6. data/bin/rhc-create-domain +3 -0
  7. data/bin/rhc-ctl-app +3 -0
  8. data/bin/rhc-ctl-domain +3 -0
  9. data/bin/rhc-domain +5 -2
  10. data/bin/rhc-domain-info +3 -0
  11. data/bin/rhc-port-forward +16 -18
  12. data/bin/rhc-snapshot +3 -0
  13. data/bin/rhc-sshkey +3 -0
  14. data/bin/rhc-tail-files +3 -0
  15. data/bin/rhc-user-info +1 -0
  16. data/features/README.md +70 -0
  17. data/features/lib/rhc_helper/app.rb +124 -0
  18. data/features/lib/rhc_helper/cartridge.rb +72 -0
  19. data/features/lib/rhc_helper/commandify.rb +154 -0
  20. data/features/lib/rhc_helper/domain.rb +50 -0
  21. data/features/lib/rhc_helper/httpify.rb +107 -0
  22. data/features/lib/rhc_helper/loggable.rb +39 -0
  23. data/features/lib/rhc_helper/persistable.rb +38 -0
  24. data/features/lib/rhc_helper/runnable.rb +41 -0
  25. data/features/lib/rhc_helper.rb +7 -0
  26. data/features/step_definitions/application_steps.rb +99 -0
  27. data/features/step_definitions/cartridge_steps.rb +42 -0
  28. data/features/step_definitions/client_steps.rb +32 -0
  29. data/features/step_definitions/domain_steps.rb +19 -0
  30. data/features/support/env.rb +99 -0
  31. data/features/verify.feature +123 -0
  32. data/lib/rhc/cli.rb +4 -1
  33. data/lib/rhc/commands/base.rb +28 -6
  34. data/lib/rhc/commands/server.rb +4 -1
  35. data/lib/rhc/commands/setup.rb +24 -0
  36. data/lib/rhc/commands.rb +10 -5
  37. data/lib/rhc/config.rb +90 -21
  38. data/lib/rhc/core_ext.rb +11 -2
  39. data/lib/rhc/coverage_helper.rb +35 -0
  40. data/lib/rhc/help_formatter.rb +30 -0
  41. data/lib/rhc/helpers.rb +41 -5
  42. data/lib/rhc/ssh_key_helpers.rb +72 -0
  43. data/lib/rhc/targz.rb +2 -8
  44. data/lib/rhc/wizard.rb +75 -58
  45. data/lib/rhc-common.rb +20 -13
  46. data/lib/rhc-rest.rb +3 -11
  47. data/spec/coverage_helper.rb +51 -0
  48. data/spec/rest_spec_helper.rb +86 -0
  49. data/spec/rhc/cli_spec.rb +19 -3
  50. data/spec/rhc/commands/server_spec.rb +2 -2
  51. data/spec/rhc/common_spec.rb +49 -0
  52. data/spec/rhc/config_spec.rb +328 -0
  53. data/spec/rhc/helpers_spec.rb +74 -1
  54. data/spec/rhc/rest_client_spec.rb +402 -0
  55. data/spec/rhc/rest_spec.rb +454 -0
  56. data/spec/rhc/targz_spec.rb +13 -0
  57. data/spec/rhc/wizard_spec.rb +305 -43
  58. data/spec/spec_helper.rb +30 -25
  59. metadata +124 -5
data/README.md CHANGED
@@ -19,7 +19,6 @@ DEPENDENCIES:
19
19
  * openssh-clients
20
20
  * ruby (1.8.7 or later)
21
21
  * rubygems
22
- * parseconfig gem
23
22
 
24
23
  Step 1: Create a domain to under which your applications will live:
25
24
 
@@ -65,3 +64,30 @@ Installing git from MacPorts/HomeBrew/Fink/etc requires Xcode.
65
64
  Now obtain the client code, either via 'git clone' as above
66
65
  or via the rhc gem.
67
66
 
67
+ ## Developing / Contributing
68
+ We expect code contributions to follow these standards:
69
+
70
+ 1. Ensure code matches the [GitHub Ruby styleguide](https://github.com/styleguide/ruby), except where the file establishes a different standard.
71
+ 2. We use RSpec for functional testing and Cucumber for our high level
72
+ integration tests. Specs are in 'spec/' and can be run with <code>bundle
73
+ exec rake spec</code>. Features are in 'features/' and can be run with
74
+ <code>bundle exec rake features</code> (although these tests runs
75
+ against the gem installed locally so you will need to gem install
76
+ first). See [README.md](https://github.com/openshift/os-client-tools/blob/master/features/README.md) in the features dir for more info.
77
+ 3. We maintain 100% line coverage of all newly added code via spec
78
+ testing. The build will fail if new code is added and it does not
79
+ have full line coverage. Some old code is currently excluded until it
80
+ can be refactored. Run <code>bundle exec rake spec</code> on Ruby 1.9+
81
+ to see your code coverage level.
82
+
83
+ Once you've made your changes:
84
+
85
+ 1. [Fork](http://help.github.com/forking/) the code
86
+ 2. Create a topic branch - `git checkout -b my_branch`
87
+ 3. Push to your branch - `git push origin my_branch`
88
+ 4. Create a [Pull Request](http://help.github.com/pull-requests/) from your branch
89
+ 5. That's it!
90
+
91
+ If you use vim, we've included a .vimrc in the root of this project.
92
+ In order to use it, install https://github.com/MarcWeber/vim-addon-local-vimrc
93
+
data/bin/rhc CHANGED
@@ -2,6 +2,7 @@
2
2
  #
3
3
  # print help
4
4
  #
5
+ require 'rhc/coverage_helper'
5
6
 
6
7
  # Require rhc-common for wizard invocation
7
8
  require 'rhc-common'
@@ -38,7 +39,7 @@ def get_args
38
39
  end
39
40
 
40
41
  def run_setup_wizard_if_needed
41
- default_setup_wizard unless ARGV.include?('--noprompt')
42
+ default_setup_wizard unless ARGV.delete('--noprompt')
42
43
  end
43
44
 
44
45
  begin
@@ -59,31 +60,22 @@ begin
59
60
  run_setup_wizard_if_needed
60
61
  system("rhc-port-forward #{get_args} 2>&1")
61
62
  retcode = $?.exitstatus
62
- when "server"
63
- run_setup_wizard_if_needed
64
- begin
65
- require 'rhc/cli'
66
- RHC::CLI.start(ARGV)
67
- retcode = 0
68
- rescue SystemExit => e
69
- retcode = e.status
70
- end
71
- when "setup"
72
- if ARGV.include?('--help') or ARGV.include?('-h') or ARGV.include?('help')
73
- puts "Usage: rhc setup"
74
- puts "Runs the setup wizard to configure your account"
75
- exit 0
76
- end
77
-
78
- w = RHC::RerunWizard.new(RHC::Config.local_config_path)
79
- success = w.run
80
- retcode = 0
81
- retcode = 1 unless success
82
63
  when "-h", "--help", "help", nil
83
64
  p_usage 0
84
65
  else
85
- puts "Invalid rhc command: #{ARGV[0]}"
86
- p_usage
66
+ if ["server", "setup"].include?(ARGV[0])
67
+ run_setup_wizard_if_needed if ARGV[0] != "setup"
68
+ begin
69
+ require 'rhc/cli'
70
+ RHC::CLI.start(ARGV)
71
+ retcode = 0
72
+ rescue SystemExit => e
73
+ retcode = e.status
74
+ end
75
+ else
76
+ puts "Invalid rhc command: #{ARGV[0]}"
77
+ p_usage
78
+ end
87
79
  end
88
80
 
89
81
  if retcode == nil
data/bin/rhc-app CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
  require 'base64'
4
7
 
@@ -93,7 +96,7 @@ def validate_args(val_type=true, val_cartridge=false, val_timeout=true)
93
96
  p_usage
94
97
  end
95
98
 
96
- debug = $opt.has_key? 'debug'
99
+ debug = true if $opt.has_key? 'debug'
97
100
  RHC::debug(debug)
98
101
 
99
102
  RHC::timeout($opt["timeout"], get_var('timeout')) if val_timeout
data/bin/rhc-chk CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
  require 'net/http'
4
7
  require 'net/https'
data/bin/rhc-create-app CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  def p_usage(error_code = 255)
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
data/bin/rhc-ctl-app CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  embed_mapper = { 'add' => 'configure', 'remove' => 'deconfigure' }
data/bin/rhc-ctl-domain CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
data/bin/rhc-domain CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
@@ -77,8 +80,8 @@ def create_or_alter_domain(alter=false)
77
80
  puts "OpenShift key found at #{ssh_key_file_path}. Reusing..."
78
81
  else
79
82
  puts "Generating OpenShift ssh key to #{ssh_key_file_path}"
80
- # Use system for interaction
81
- system("ssh-keygen -t rsa -f '#{ssh_key_file_path}'")
83
+ w = RHC::SSHWizard.new($opt['rhlogin'], $password)
84
+ w.run
82
85
  end
83
86
 
84
87
  ssh_keyfile_contents = File.open(ssh_pub_key_file_path).gets.chomp.split(' ')
data/bin/rhc-domain-info CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
data/bin/rhc-port-forward CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
@@ -86,7 +89,7 @@ end
86
89
 
87
90
  # mock for windows
88
91
  if defined?(UNIXServer) != 'constant' or UNIXServer.class != Class
89
- class UNIXServer; end
92
+ class UNIXServer; end
90
93
  end
91
94
 
92
95
  app_uuid = user_info['app_info'][app_name]['uuid']
@@ -108,21 +111,17 @@ Net::SSH.start(ssh_host, app_uuid) do |ssh|
108
111
 
109
112
  ssh.exec! "rhc-list-ports" do |channel, stream, data|
110
113
 
111
- # data comes from a linux server so it is a one-line string for windows, we need to split \n manually
112
- if RHC::Helpers.windows?
113
- data = data.split /\n/
114
- end
115
-
116
114
  if stream == :stderr
117
115
 
118
- data.each { |line|
116
+ data.lines { |line|
117
+
119
118
  line = line.chomp
120
119
 
121
120
  if line.downcase =~ /permission denied/
122
121
  puts line
123
122
  exit 1
124
123
  end
125
-
124
+
126
125
  if line.index(ip_and_port_simple_regex)
127
126
  hosts_and_ports_descriptions << line
128
127
  end
@@ -130,7 +129,8 @@ Net::SSH.start(ssh_host, app_uuid) do |ssh|
130
129
 
131
130
  else
132
131
 
133
- data.each { |line|
132
+ data.lines { |line|
133
+
134
134
  line = line.chomp
135
135
 
136
136
  if line.downcase =~ /scale/
@@ -149,18 +149,15 @@ Net::SSH.start(ssh_host, app_uuid) do |ssh|
149
149
  end
150
150
 
151
151
  scaled_uuids.each { |scaled_uuid|
152
-
152
+
153
153
  puts "Using #{scaled_uuid}@#{ssh_host} (scaled instance)..." if debug
154
154
 
155
155
  Net::SSH.start(ssh_host, scaled_uuid) do |ssh|
156
156
 
157
157
  ssh.exec! "rhc-list-ports" do |channel, stream, data|
158
- # data comes from a linux server so it is a one-line string for windows, we need to split \n manually
159
- if RHC::Helpers.windows?
160
- data = data.split /\n/
161
- end
162
158
  if stream == :stderr
163
- data.each { |line|
159
+ data.lines { |line|
160
+
164
161
  line = line.chomp
165
162
  if line.downcase =~ /permission denied/
166
163
  puts line
@@ -171,7 +168,8 @@ Net::SSH.start(ssh_host, app_uuid) do |ssh|
171
168
  end
172
169
  }
173
170
  else
174
- data.each { |line|
171
+ data.lines { |line|
172
+
175
173
  line = line.chomp
176
174
  if ip_and_port_simple_regex.match(line)
177
175
  hosts_and_ports << line
@@ -202,12 +200,12 @@ Net::SSH.start(ssh_host, app_uuid) do |ssh|
202
200
  end
203
201
  ssh.loop { true }
204
202
  end
205
-
203
+
206
204
  rescue Interrupt
207
205
  puts
208
206
  puts "Terminating..."
209
207
  exit 0
210
-
208
+
211
209
  rescue Exception => e
212
210
  puts
213
211
  puts e.message if debug
data/bin/rhc-snapshot CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
data/bin/rhc-sshkey CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
 
4
7
  #
data/bin/rhc-tail-files CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ require 'rhc/coverage_helper'
4
+
2
5
  require 'rhc-common'
3
6
  require 'base64'
4
7
 
data/bin/rhc-user-info CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # print deprecation warning
3
+
3
4
  puts "Warning: This command is deprecated. Please use rhc-domain-info instead."
4
5
  puts""
5
6
 
@@ -0,0 +1,70 @@
1
+ Overview
2
+ ==============
3
+
4
+ These tests can be run against a production or OpenShift Origin instance for
5
+ verification of basic functionality. These tests should be operating system
6
+ independent and will shell out to execute the 'rhc *' commands to emulate a
7
+ user as closely as possible. These tests exercise both the commandline
8
+ client and the underlying infrastructure and serve as integration level
9
+ verification tests for the entire stack.
10
+
11
+ Usage
12
+ =============
13
+
14
+ Run from the base directory with
15
+
16
+ <env variables> bundle exec rake features
17
+
18
+ 'features' requires RHC_USERNAME+RHC_PASSWORD+RHC_NAMESPACE or
19
+ RHC_ENDPOINT to be set in the environment.
20
+
21
+ Using a proxy
22
+ --------------
23
+
24
+ You can use a proxy by setting the http_proxy environment variable. For example
25
+
26
+ http_proxy='http://proxyserver:proxyport/' bundle exec rake features
27
+
28
+ Pre-defined users
29
+ -----------------
30
+
31
+ In many cases, these tests will be run with an existing, pre-created user. The
32
+ tests should keep the resource needs of that user to a minimum, but in some
33
+ cases, the user might need to have an increased number of gears added to
34
+ support certain tests.
35
+
36
+ You use environment variables to notify the tests of the well defined user,
37
+ password and namespace. This can be done by passing the values in before the
38
+ command:
39
+
40
+ RHC_USERNAME='mylogin@example.com' RHC_PASSWORD='supersecretpassword' RHC_NAMESPACE='mynamespace' bundle exec rake features
41
+
42
+ Development Usage
43
+ =================
44
+
45
+ In development, you probably aren't going to be running against production systems.
46
+ You will most likely be running against your own OpenShift Origin system. To be
47
+ able to point to a custom system, you can configure the REST endpoint that is used.
48
+ If not specified, it will default to the OpenShift Production REST Endpoint:
49
+
50
+ RHC_ENDPOINT='https://myserver/rest/api' bundle exec rake features
51
+
52
+
53
+ Developing tests
54
+ ----------------
55
+
56
+ Often when you are developing new tests, you don't want to run the entire suite
57
+ each time. However, the tests by default automatically clean up the test
58
+ applications that were created on the previous run. You can quickly develop
59
+ and interate on a single test by doing the following:
60
+
61
+ * Run the initialization portion of the test suite
62
+
63
+ RHC_ENDPOINT='https://yourserver/rest/api' bundle exec cucumber -t @init
64
+
65
+ * Run the tests on your specific feature without reset state and using the
66
+ created username and namespace from the previous run. For example, if the
67
+ cucumber feature you wanted to test started on line 17, in your .feature file,
68
+ you would run
69
+
70
+ RHC_USERNAME=`cat /tmp/rhc/username` RHC_NAMESPACE=`cat /tmp/rhc/namespace` RHC_ENDPOINT='https://yourserver/rest/api' NO_CLEAN=1 bundle exec cucumber features/verify.feature:20
@@ -0,0 +1,124 @@
1
+ require 'tmpdir'
2
+ require 'rhc-rest'
3
+
4
+ module RHCHelper
5
+ #
6
+ # Constant Definitions
7
+ #
8
+ TEMP_DIR = File.join(Dir.tmpdir, "rhc")
9
+
10
+ #
11
+ # A class to help maintain the state from rhc calls and helper
12
+ # methods around application management.
13
+ #
14
+ class App
15
+ extend Persistable
16
+ extend Runnable
17
+ include Loggable
18
+ include Commandify
19
+ include Runnable
20
+ include Persistify
21
+ include Httpify
22
+
23
+ # attributes to represent the general information of the application
24
+ attr_accessor :name, :type, :hostname, :repo, :embed, :snapshot, :uid, :alias
25
+
26
+ # mysql connection information
27
+ attr_accessor :mysql_hostname, :mysql_user, :mysql_password, :mysql_database
28
+
29
+ # Create the data structure for a test application
30
+ def initialize(type, name)
31
+ @name, @type = name, type
32
+ @hostname = "#{name}-#{$namespace}.#{$domain}"
33
+ @repo = "#{TEMP_DIR}/#{$namespace}_#{name}_repo"
34
+ @file = "#{TEMP_DIR}/#{$namespace}.json"
35
+ @embed = []
36
+ @embed_helpers = {}
37
+ end
38
+
39
+ def self.rhc_setup
40
+ # Setup questions asked by wizard which are passed in below:
41
+ # 1 - username
42
+ # 2 - password
43
+ # 3 - upload SSH keys
44
+ # 4 - if no namespace is found, create namespace? (blank is no)
45
+ if $namespace
46
+ # Namespace is already created, so don't pass anything in
47
+ logger.info("Namespace (#{$namespace}) should be found by the wizard")
48
+ run("rhc setup", nil, [$username, $password, 'yes', ""])
49
+ else
50
+ # Pass in a blank value for namespace to create in the next step
51
+ logger.info("Skipping namespace creation")
52
+ run("rhc setup", nil, [$username, $password, 'yes', "", ""])
53
+ end
54
+ end
55
+
56
+ def self.create_unique(type, prefix="test")
57
+ # Get a REST client to verify the application name
58
+ client = Rhc::Rest::Client.new($end_point, $username, $password)
59
+
60
+ # Cleanup all test applications
61
+ test_names = []
62
+ client.domains.each do |domain|
63
+ domain.applications.each do |app|
64
+ test_names << app.name if app.name.start_with?(prefix)
65
+ end
66
+ end
67
+
68
+ loop do
69
+ # Generate a random application name
70
+ chars = ("1".."9").to_a
71
+ name = prefix + Array.new(8, '').collect{chars[rand(chars.size)]}.join
72
+
73
+ # If the test name exists, try again
74
+ next if test_names.index(name)
75
+
76
+ # Create the app
77
+ app = App.new(type, name)
78
+ app.persist
79
+ return app
80
+ end
81
+ end
82
+
83
+ def add_cartridge(name)
84
+ exitcode = 0
85
+ cartridge(name).add do |ec|
86
+ exitcode = ec
87
+ embed << name unless embed.include?(name) or ec != 0
88
+ end
89
+
90
+ persist
91
+ exitcode
92
+ end
93
+
94
+ def remove_cartridge(name)
95
+ cartridge(name).remove
96
+ embed.reject! { |s| s == name }
97
+
98
+ persist
99
+ end
100
+
101
+ def cartridge(name)
102
+ @embed_helpers[name] = RHCHelper::Cartridge.new(self, name) unless @embed_helpers.include?(name)
103
+ @embed_helpers[name]
104
+ end
105
+
106
+ def get_index_file
107
+ case @type
108
+ when "php-5.3" then "php/index.php"
109
+ when "ruby-1.8" then "config.ru"
110
+ when "python-2.6" then "wsgi/application"
111
+ when "perl-5.10" then "perl/index.pl"
112
+ when "jbossas-7" then "src/main/webapp/index.html"
113
+ when "jbosseap-6.0" then "src/main/webapp/index.html"
114
+ when "nodejs-0.6" then "index.html"
115
+ end
116
+ end
117
+
118
+ def get_mysql_file
119
+ case @type
120
+ when "php-5.3" then File.expand_path("../misc/php/db_test.php", File.expand_path(File.dirname(__FILE__)))
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,72 @@
1
+ require 'tmpdir'
2
+ require 'rhc-rest'
3
+
4
+ module RHCHelper
5
+ #
6
+ # Constant Definitions
7
+ #
8
+ TEMP_DIR = File.join(Dir.tmpdir, "rhc")
9
+
10
+ #
11
+ # A class to help maintain the state from rhc calls and helper
12
+ # methods around cartridge management.
13
+ #
14
+ class Cartridge
15
+ extend Runnable
16
+ extend Persistable
17
+ include Loggable
18
+ include Runnable
19
+ include Httpify
20
+ include Persistify
21
+
22
+ # attributes to represent the general information of the cartridge
23
+ attr_accessor :name
24
+
25
+ # Create the data structure for a test cartridge
26
+ def initialize(app, name)
27
+ @name = name
28
+ @app_name = app.name
29
+ @hostname = "#{@app_name}-#{$namespace}.#{$domain}"
30
+ @file = "#{TEMP_DIR}/#{$namespace}.json"
31
+ end
32
+
33
+ def rhc_app_cartridge(cmd)
34
+ full_cmd = "rhc app cartridge #{cmd} -l #{$username} -p #{$password} -a #{@app_name}"
35
+ full_cmd += " -c #{@name}" if cmd != "list"
36
+ run(full_cmd, nil) do |exitstatus, out, err, arg|
37
+ yield exitstatus, out, err, arg if block_given?
38
+ end
39
+ end
40
+
41
+ def add
42
+ rhc_app_cartridge('add') do |exitstatus, out, err, arg|
43
+ yield exitstatus, out, err, arg if block_given?
44
+ end
45
+ end
46
+
47
+ def status
48
+ result = ""
49
+ rhc_app_cartridge('status') do |exitstatus, out, err, arg|
50
+ result = out
51
+ end
52
+
53
+ result
54
+ end
55
+
56
+ def start
57
+ rhc_app_cartridge('start')
58
+ end
59
+
60
+ def stop
61
+ rhc_app_cartridge('stop')
62
+ end
63
+
64
+ def restart
65
+ rhc_app_cartridge('restart')
66
+ end
67
+
68
+ def remove
69
+ rhc_app_cartridge('remove')
70
+ end
71
+ end
72
+ end