startapp 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,20 @@
1
+ require 'rhc/commands/base'
2
+
3
+ module RHC::Commands
4
+ class Apps < Base
5
+ summary "List all your applications"
6
+ description "Display the list of applications that you own. Includes information about each application."
7
+ def run
8
+ applications = rest_client.applications(:include => :cartridges).sort
9
+
10
+ info "In order to deploy applications, you must create a domain with 'app setup' or 'app create-domain'." and return 1 if applications.empty? && rest_client.domains.empty?
11
+
12
+ applications.each{ |a| display_app(a, a.cartridges) }.blank? and
13
+ info "No applications. Use 'app create-app'." and
14
+ return 1
15
+
16
+ success "You have #{applications.length} applications"
17
+ 0
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,115 @@
1
+ module RHC::Commands
2
+ class Authorization < Base
3
+
4
+ summary "Manage your authorization tokens"
5
+ syntax "<action>"
6
+ description <<-DESC
7
+ An authorization token grants access to the StartApp REST API with a
8
+ set of privileges called 'scopes' for a limited time. You can add an
9
+ optional note to each authorization token to assist you in remembering
10
+ why it was created.
11
+
12
+ To see all your authorizations, run 'app authorizations'.
13
+
14
+ To view the list of scopes supported by this server, run the
15
+ 'app add-authorization' command with no arguments.
16
+
17
+ These commands manage your authorization tokens on the server - if you
18
+ want to clear your authorization tokens from the current machine use
19
+ 'app logout'
20
+ DESC
21
+ default_action :help
22
+
23
+ summary "Show the authorization tokens for your account"
24
+ description <<-DESC
25
+ Shows the full list of authorization tokens on your account. You
26
+ can add, edit, or delete authorizations with subcommands.
27
+
28
+ An authorization token grants access to the StartApp REST API with
29
+ a set of privileges called 'scopes' for a limited time. You can
30
+ add an optional note to each authorization token to assist you in
31
+ remembering what is available.
32
+ DESC
33
+ alias_action 'authorizations', :root_command => true
34
+
35
+ def list
36
+ rest_client.authorizations.each{ |auth| paragraph{ display_authorization(auth, token_for_user) } } or info "No authorizations"
37
+
38
+ 0
39
+ end
40
+
41
+ option "--scopes SCOPES", "A comma delimited list of scopes (e.g. 'scope1,scope2')"
42
+ option "--note NOTE", "A description of this authorization (optional)"
43
+ option "--expires-in SECONDS", "The number of seconds before this authorization expires (optional)"
44
+ summary "Add an authorization to your account"
45
+ syntax "--scopes SCOPES [--note NOTE] [--expires-in SECONDS]"
46
+ description <<-DESC
47
+ Add an authorization to your account. An authorization token grants
48
+ access to the StartApp REST API with a set of privileges called 'scopes'
49
+ for a limited time. You can add an optional note to each authorization
50
+ token to assist you in remembering what is available.
51
+
52
+ To view the list of scopes supported by this server, run this command
53
+ without any options.
54
+
55
+ You may pass multiple scopes to the --scopes option inside of double
56
+ quotes (--scopes \"scope1 scope2\") or by separating them with commas
57
+ (--scopes scope1,scope2).
58
+
59
+ The server will enforce a maximum and default expiration that may
60
+ differ for each scope. If you request an expiration longer than the
61
+ server maximum, you will be given the default value.
62
+ DESC
63
+ def add
64
+ unless options.scopes.to_s.strip.present?
65
+ say "When adding an authorization, you must specify which permissions clients will have."
66
+ scope_help
67
+ say "Run 'app authorization add --help' to see more options"
68
+ return 0
69
+ end
70
+
71
+ say "Adding authorization ... "
72
+ auth = rest_client.add_authorization(:scope => options.scopes, :note => options.note, :expires_in => options.expires_in)
73
+ success "done"
74
+ paragraph{ display_authorization(auth) }
75
+
76
+ 0
77
+ end
78
+
79
+ summary "Delete one or more authorization tokens"
80
+ syntax "<token_or_id> [...<token_or_id>]"
81
+ description <<-DESC
82
+ Delete one or more of the authorization tokens associated with
83
+ your account. After deletion, any clients using the token will
84
+ no longer have access to StartApp and will need to reauthenticate.
85
+ DESC
86
+ argument :auth_token, "The token you wish to delete", ['--auth-token TOKEN'], :type => :list
87
+ def delete(tokens)
88
+ raise ArgumentError, "You must specify one or more tokens to delete" if tokens.blank?
89
+ say "Deleting authorization ... "
90
+ tokens.each{ |token| rest_client.delete_authorization(token) }
91
+ success "done"
92
+ 0
93
+ end
94
+
95
+ summary "Delete all authorization tokens from your account"
96
+ description <<-DESC
97
+ Delete all the authorization tokens associated with your account.
98
+ After deletion, any clients using those tokens will need to
99
+ reauthenticate.
100
+ DESC
101
+ def delete_all
102
+ say "Deleting all authorizations ... "
103
+ rest_client.delete_authorizations
104
+ success "done"
105
+ 0
106
+ end
107
+
108
+ protected
109
+ def scope_help
110
+ descriptions = rest_client.authorization_scope_list
111
+ paragraph{ say table(descriptions, :header => ['Scope', 'Description']) }
112
+ paragraph{ say "You may pass multiple scopes to the --scopes option inside of double quotes (--scopes \"scope1 scope2\") or by separating them with commas (--scopes scope1,scope2)." }
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,174 @@
1
+ require 'commander'
2
+ require 'commander/delegates'
3
+ require 'rhc/helpers'
4
+ require 'rhc/wizard'
5
+ require 'rhc/config'
6
+ require 'rhc/commands'
7
+ require 'rhc/exceptions'
8
+ require 'rhc/context_helper'
9
+
10
+ class RHC::Commands::Base
11
+
12
+ attr_writer :options, :config
13
+
14
+ def initialize(options=Commander::Command::Options.new,
15
+ config=RHC::Config.new)
16
+ @options, @config = options, config
17
+ end
18
+
19
+ protected
20
+ include RHC::Helpers
21
+ include RHC::ContextHelpers
22
+
23
+ attr_reader :options, :config
24
+
25
+ # Return a client object capable of making calls
26
+ # to the OpenShift API that transforms intent
27
+ # and options, to remote calls, and then handle
28
+ # the output (or failures) into exceptions and
29
+ # formatted object output. Most interactions
30
+ # should be through this call pattern.
31
+ def rest_client(opts={})
32
+ @rest_client ||= begin
33
+ auth = RHC::Auth::Basic.new(options)
34
+ auth = RHC::Auth::Token.new(options, auth, token_store) if (options.use_authorization_tokens || options.token) && !(options.rhlogin && options.password)
35
+ debug "Authenticating with #{auth.class}"
36
+ client_from_options(:auth => auth)
37
+ end
38
+
39
+ if opts[:min_api] && opts[:min_api].to_f > @rest_client.api_version_negotiated.to_f
40
+ raise RHC::ServerAPINotSupportedException.new(opts[:min_api], @rest_client.api_version_negotiated)
41
+ end
42
+
43
+ @rest_client
44
+ end
45
+
46
+ def token_store
47
+ @token_store ||= RHC::Auth::TokenStore.new(config.home_conf_path)
48
+ end
49
+
50
+ def help(*args)
51
+ raise ArgumentError, "Please specify an action to take"
52
+ end
53
+
54
+ class InvalidCommand < StandardError ; end
55
+
56
+ def self.method_added(method)
57
+ return if self == RHC::Commands::Base
58
+ return if private_method_defined? method
59
+ return if protected_method_defined? method
60
+
61
+ prefix = self.object_name
62
+ method_name = method.to_s == 'run' ? nil : method.to_s.gsub("_", "-")
63
+ name = [prefix, method_name].compact
64
+ raise InvalidCommand, "Either object_name must be set or a non default method defined" if name.empty?
65
+
66
+ aliases.each{ |a| a[:action].unshift(prefix) unless a[:root_command] } if prefix
67
+
68
+ RHC::Commands.add((@options || {}).merge({
69
+ :name => name,
70
+ :class => self,
71
+ :method => method
72
+ }));
73
+
74
+ @options = nil
75
+ end
76
+
77
+ def self.object_name(value=nil)
78
+ @object_name ||= begin
79
+ value ||= if self.name && !self.name.empty?
80
+ self.name.split('::').last
81
+ end
82
+ value.to_s.split(/(?=[A-Z])/).join('-').downcase if value
83
+ end
84
+ end
85
+
86
+ def self.description(*args)
87
+ o = args.join(' ')
88
+ options[:description] = o.strip_heredoc
89
+ end
90
+ def self.summary(value)
91
+ options[:summary] = value
92
+ end
93
+ def self.syntax(value)
94
+ options[:syntax] = value
95
+ end
96
+ #def self.deprecated(msg)
97
+ # options[:deprecated] = msg
98
+ #end
99
+ def self.suppress_wizard
100
+ @suppress_wizard = true
101
+ end
102
+
103
+ def self.suppress_wizard?
104
+ @suppress_wizard
105
+ end
106
+
107
+ #
108
+ # Provide an alias to the command. The alias will not be shown in help, but will
109
+ # be available in autocompletion and at execution time.
110
+ #
111
+ # Supported options:
112
+ #
113
+ # :deprecated - if true, a warning will be displayed when the command is executed
114
+ # :root_command - if true, do not prepend the object name to the command
115
+ #
116
+ def self.alias_action(action, options={})
117
+ options[:action] = action.is_a?(Array) ? action : action.to_s.split(' ')
118
+ aliases << options
119
+ end
120
+
121
+ def self.option(switches, description, options={})
122
+ options_metadata << {:switches => switches,
123
+ :description => description,
124
+ :required => options[:required],
125
+ :covered_by => options[:covered_by],
126
+ :deprecated => options[:deprecated],
127
+ :type => options[:type],
128
+ :hide => options[:hide],
129
+ :default => options[:default],
130
+ }
131
+ end
132
+
133
+ def self.argument(name, description, switches=[], options={})
134
+ arg_type = options[:type]
135
+
136
+ option_symbol = Commander::Runner.switch_to_sym(switches.last)
137
+ args_metadata << {:name => name,
138
+ :description => description,
139
+ :switches => switches,
140
+ :option_symbol => option_symbol,
141
+ :covered_by => options[:covered_by],
142
+ :optional => options[:optional],
143
+ :default => options[:default],
144
+ :allow_nil => options[:allow_nil],
145
+ :hide => options[:hide],
146
+ :type => arg_type}
147
+ end
148
+
149
+ def self.default_action(action)
150
+ options[:default] = action unless action == :help
151
+ name = self.object_name
152
+ raise InvalidCommand, "object_name must be set" if name.empty?
153
+
154
+ RHC::Commands.add((@options || {}).merge({
155
+ :name => name,
156
+ :class => self,
157
+ :method => options[:default]
158
+ }));
159
+ end
160
+
161
+ private
162
+ def self.options_metadata
163
+ options[:options] ||= []
164
+ end
165
+ def self.args_metadata
166
+ options[:args] ||= []
167
+ end
168
+ def self.aliases
169
+ options[:aliases] ||= []
170
+ end
171
+ def self.options
172
+ @options ||= {}
173
+ end
174
+ end
@@ -0,0 +1,329 @@
1
+ require 'rhc/commands/base'
2
+ require 'rhc/cartridge_helpers'
3
+
4
+ module RHC::Commands
5
+ class Cartridge < Base
6
+ summary "Manage your application cartridges"
7
+ syntax "<action>"
8
+ description <<-DESC
9
+ Cartridges add functionality to StartApp applications. Each application
10
+ has one web cartridge to listen for HTTP requests, and any number
11
+ of addon cartridges. Addons may include databases like MySQL and Mongo,
12
+ administrative tools like phpMyAdmin, or build clients like Jenkins.
13
+
14
+ Most cartridges that listen for incoming network traffic are placed on
15
+ one or more gears (a small server instance). Other cartridges may be
16
+ available across all of the gears of an application to listen for changes
17
+ (like Jenkins) or provide environment variables.
18
+
19
+ Use the 'cartridges' command to see a list of all available cartridges.
20
+ Add a new cartridge to your application with 'add-cartridge'. StartApp
21
+ also supports downloading cartridges - pass a URL in place of the cartridge
22
+ name and we'll download and install that cartridge into your app. Keep
23
+ in mind that these cartridges receive no security updates. Note that
24
+ not all StartApp servers allow downloaded cartridges.
25
+
26
+ For scalable applications, use the 'cartridge-scale' command on the web
27
+ cartridge to set the minimum and maximum scale.
28
+
29
+ Commands that affect a cartridge within an application will affect all
30
+ gears the cartridge is installed to.
31
+ DESC
32
+ default_action :help
33
+
34
+ summary "List available cartridges"
35
+ syntax ''
36
+ option ["-v", "--verbose"], "Display more details about each cartridge"
37
+ alias_action :"app cartridge list", :root_command => true, :deprecated => true
38
+ alias_action :"cartridges", :root_command => true
39
+ def list
40
+ carts = rest_client.cartridges.sort_by{ |c| "#{c.type == 'standalone' && 1}_#{c.tags.include?('experimental') ? 1 : 0}_#{(c.display_name || c.name).downcase}" }
41
+
42
+ pager
43
+
44
+ if options.verbose
45
+ carts.each do |c|
46
+ paragraph do
47
+ name = c.name
48
+ name += '*' if c.usage_rate?
49
+ name = c.display_name != c.name && "#{color(c.display_name, :cyan)} [#{name}]" || name
50
+ tags = c.tags - RHC::Rest::Cartridge::HIDDEN_TAGS
51
+ say header([name, "(#{c.only_in_existing? ? 'addon' : 'web'})"])
52
+ say c.description
53
+ paragraph{ say "Tagged with: #{tags.sort.join(', ')}" } if tags.present?
54
+ paragraph{ say format_usage_message(c) } if c.usage_rate?
55
+ paragraph{ warn "Does not receive automatic security updates" } unless c.automatic_updates?
56
+ end
57
+ end
58
+ else
59
+ say table(carts.collect do |c|
60
+ [[c.name, c.usage_rate? ? " (*)" : "", c.automatic_updates? ? '' : ' (!)'].join(''),
61
+ c.display_name,
62
+ c.only_in_existing? ? 'addon' : 'web',
63
+ ]
64
+ end)
65
+ end
66
+
67
+ paragraph{ say "Note: Web cartridges can only be added to new applications." }
68
+ paragraph{ say "(*) denotes a cartridge with additional usage costs." } if carts.any?(&:usage_rate?)
69
+ paragraph{ say "(!) denotes a cartridge that will not receive automatic security updates." } unless options.verbose || carts.none?(&:automatic_updates?)
70
+
71
+ 0
72
+ end
73
+
74
+ summary "Add a cartridge to your application"
75
+ syntax "<cartridge_type> [--namespace NAME] [--app NAME]"
76
+ takes_application
77
+ option ["-e", "--env VARIABLE=VALUE"], "Environment variable(s) to be set on this cartridge, or path to a file containing environment variables", :type => :list
78
+ option ["-g", "--gear-size SIZE"], "Gear size controls how much memory and CPU your cartridge can use"
79
+ argument :cart_type, "The type of the cartridge you are adding (run 'app cartridge list' to obtain a list of available cartridges)", ["-c", "--cartridge cart_type"]
80
+ alias_action :"app cartridge add", :root_command => true, :deprecated => true
81
+ def add(cart_type)
82
+ cart = check_cartridges(cart_type, :from => not_standalone_cartridges).first
83
+
84
+ say "Adding #{cart.short_name} to application '#{options.app}' ... "
85
+
86
+ say format_usage_message(cart) if cart.usage_rate?
87
+
88
+ rest_app = find_app(:include => :cartridges)
89
+
90
+ supports_env_vars = rest_app.supports_add_cartridge_with_env_vars?
91
+ supports_gear_size = rest_app.supports_add_cartridge_with_gear_size?
92
+
93
+ cart.environment_variables = collect_env_vars(options.env).map { |item| item.to_hash } if options.env && supports_env_vars
94
+ cart.gear_size = options.gear_size if options.gear_size && supports_gear_size
95
+
96
+ rest_cartridge = rest_app.add_cartridge(cart)
97
+
98
+ success "done"
99
+
100
+ rest_cartridge.environment_variables = cart.environment_variables if cart.environment_variables.present?
101
+
102
+ paragraph{ display_cart(rest_cartridge) }
103
+ paragraph{ say "Use 'app env --help' to manage environment variable(s) on this cartridge and application." } if cart.environment_variables.present?
104
+ paragraph{ warn "Server does not support environment variables." if options.env && !supports_env_vars }
105
+ paragraph{ warn "Server does not support gear sizes for cartridges." if options.gear_size && !supports_gear_size }
106
+ paragraph{ rest_cartridge.messages.each { |msg| success msg } }
107
+
108
+ 0
109
+ end
110
+
111
+ summary "Show useful information about a cartridge"
112
+ syntax "<cartridge> [--namespace NAME] [--app NAME]"
113
+ takes_application
114
+ argument :cartridge, "The name of the cartridge", ["-c", "--cartridge cart_type"]
115
+ def show(cartridge)
116
+ rest_app = find_app(:include => :cartridges)
117
+ rest_cartridge = check_cartridges(cartridge, :from => rest_app.cartridges).first
118
+
119
+ display_cart(rest_cartridge)
120
+
121
+ 0
122
+ end
123
+
124
+ summary "Remove a cartridge from your application"
125
+ syntax "<cartridge> [--namespace NAME] [--app NAME]"
126
+ argument :cartridge, "The name of the cartridge you are removing", ["-c", "--cartridge cartridge"]
127
+ takes_application
128
+ option ["--confirm"], "Pass to confirm removing the cartridge"
129
+ alias_action :"app cartridge remove", :root_command => true, :deprecated => true
130
+ def remove(cartridge)
131
+ rest_app = find_app(:include => :cartridges)
132
+ rest_cartridge = check_cartridges(cartridge, :from => rest_app.cartridges).first
133
+
134
+ confirm_action "Removing a cartridge is a destructive operation that may result in loss of data associated with the cartridge.\n\nAre you sure you wish to remove #{rest_cartridge.name} from '#{rest_app.name}'?"
135
+
136
+ say "Removing #{rest_cartridge.name} from '#{rest_app.name}' ... "
137
+ rest_cartridge.destroy
138
+ success "removed"
139
+
140
+ paragraph{ rest_cartridge.messages.each { |msg| success msg } }
141
+
142
+ 0
143
+ end
144
+
145
+ summary "Start a cartridge"
146
+ syntax "<cartridge> [--namespace NAME] [--app NAME]"
147
+ argument :cart_type, "The name of the cartridge you are stopping", ["-c", "--cartridge cartridge"]
148
+ takes_application
149
+ alias_action :"app cartridge start", :root_command => true, :deprecated => true
150
+ def start(cartridge)
151
+ cartridge_action(cartridge, :start, 'Starting %s ... ')
152
+ 0
153
+ end
154
+
155
+ summary "Stop a cartridge"
156
+ syntax "<cartridge> [--namespace NAME] [--app NAME]"
157
+ argument :cart_type, "The name of the cartridge you are stopping", ["-c", "--cartridge cartridge"]
158
+ takes_application
159
+ alias_action :"app cartridge stop", :root_command => true, :deprecated => true
160
+ def stop(cartridge)
161
+ cartridge_action(cartridge, :stop, 'Stopping %s ... ')
162
+ 0
163
+ end
164
+
165
+ summary "Restart a cartridge"
166
+ syntax "<cartridge_type> [--namespace NAME] [--app NAME]"
167
+ argument :cart_type, "The name of the cartridge you are restarting", ["-c", "--cartridge cartridge"]
168
+ takes_application
169
+ alias_action :"app cartridge restart", :root_command => true, :deprecated => true
170
+ def restart(cartridge)
171
+ cartridge_action(cartridge, :restart, 'Restarting %s ... ')
172
+ 0
173
+ end
174
+
175
+ summary "Get current the status of a cartridge"
176
+ syntax "<cartridge> [--namespace NAME] [--app NAME]"
177
+ argument :cart_type, "The name of the cartridge you are getting the status of", ["-c", "--cartridge cartridge"]
178
+ takes_application
179
+ alias_action :"app cartridge status", :root_command => true, :deprecated => true
180
+ def status(cartridge)
181
+ rest_app = find_app(:include => :cartridges)
182
+ rest_cartridge = check_cartridges(cartridge, :from => rest_app.cartridges).first
183
+ results { rest_cartridge.status.each{ |msg| say msg['message'] } }
184
+ 0
185
+ end
186
+
187
+ summary "Reload the cartridge's configuration"
188
+ syntax "<cartridge> [--namespace NAME] [--app NAME]"
189
+ argument :cart_type, "The name of the cartridge you are reloading", ["-c", "--cartridge cartridge"]
190
+ takes_application
191
+ alias_action :"app cartridge reload", :root_command => true, :deprecated => true
192
+ def reload(cartridge)
193
+ cartridge_action(cartridge, :reload, 'Reloading %s ... ')
194
+ 0
195
+ end
196
+
197
+ summary "Set the scale range for a cartridge"
198
+ description <<-DESC
199
+ Each cartridge capable of scaling may have a minimum and a maximum set, although within that range
200
+ each type of cartridge may make decisions to autoscale. Web cartridges will scale based on incoming
201
+ request traffic - see https://www.openshift.com/developers/scaling for more information. Non web
202
+ cartridges such as databases may require specific increments of scaling (1, 3, 5) in order to
203
+ properly function. Please consult the cartridge documentation for more on specifics of scaling.
204
+
205
+ Set both values the same to guarantee a scale value. You may specify both values with the argument
206
+ 'multiplier' or use '--min' and '--max' independently.
207
+
208
+ Scaling may take several minutes or more if the server must provision multiple gears. Your operation
209
+ will continue in the background if your client is disconnected.
210
+ DESC
211
+ syntax "<cartridge> [multiplier] [--namespace NAME] [--app NAME] [--min min] [--max max]"
212
+ argument :cartridge, "The name of the cartridge you are scaling", ["-c", "--cartridge cartridge"]
213
+ argument :multiplier, "The number of instances of this cartridge you need", [], :optional => true, :hide => true
214
+ takes_application
215
+ option ["--min min", Integer], "Minimum scaling value"
216
+ option ["--max max", Integer], "Maximum scaling value"
217
+ def scale(cartridge, multiplier)
218
+ options.default(:min => Integer(multiplier), :max => Integer(multiplier)) if multiplier rescue raise ArgumentError, "Multiplier must be a positive integer."
219
+
220
+ raise RHC::MissingScalingValueException unless options.min || options.max
221
+
222
+ rest_app = find_app(:include => :cartridges)
223
+ rest_cartridge = check_cartridges(cartridge, :from => rest_app.cartridges).first
224
+
225
+ raise RHC::CartridgeNotScalableException unless rest_cartridge.scalable?
226
+
227
+ warn "This operation will run until the application is at the minimum scale and may take several minutes."
228
+ say "Setting scale range for #{rest_cartridge.name} ... "
229
+
230
+ cart = rest_cartridge.set_scales({
231
+ :scales_from => options.min,
232
+ :scales_to => options.max
233
+ })
234
+
235
+ success "done"
236
+ paragraph{ display_cart(cart) }
237
+
238
+ 0
239
+ rescue RHC::Rest::TimeoutException => e
240
+ raise unless e.on_receive?
241
+ info "The server has closed the connection, but your scaling operation is still in progress. Please check the status of your operation via 'app show-app'."
242
+ 1
243
+ end
244
+
245
+ summary 'View/manipulate storage on a cartridge'
246
+ syntax '<cartridge> -a app [--show] [--add|--remove|--set amount] [--namespace NAME]'
247
+ argument :cart_type, "The name of the cartridge", ["-c", "--cartridge cart_type"], :type => :list
248
+ takes_application
249
+ option ["--show"], "Show the current base and additional storage capacity"
250
+ option ["--add amount"], "Add the indicated amount to the additional storage capacity"
251
+ option ["--remove amount"], "Remove the indicated amount from the additional storage capacity"
252
+ option ["--set amount"], "Set the specified amount of additional storage capacity"
253
+ option ["-f", "--force"], "Force the action"
254
+ def storage(cartridge)
255
+ cartridges = Array(cartridge)
256
+ rest_client(:min_api => 1.3).api
257
+ rest_app = find_app(:include => :cartridges)
258
+
259
+ # Pull the desired action
260
+ #
261
+ actions = options.__hash__.keys & [:show, :add, :remove, :set]
262
+
263
+ # Ensure that only zero or one action was selected
264
+ raise RHC::AdditionalStorageArgumentsException if actions.length > 1
265
+
266
+ operation = actions.first || :show
267
+ amount = options.__hash__[operation]
268
+
269
+ # Perform a storage change action if requested
270
+ if operation == :show
271
+ results do
272
+ if cartridges.length == 0
273
+ display_cart_storage_list rest_app.cartridges
274
+ else
275
+ check_cartridges(cartridge, :from => rest_app.cartridges).each do |cart|
276
+ display_cart_storage_info cart, cart.display_name
277
+ end
278
+ end
279
+ end
280
+ else
281
+ raise RHC::MultipleCartridgesException,
282
+ 'Exactly one cartridge must be specified for this operation' if cartridges.length != 1
283
+
284
+ rest_cartridge = check_cartridges(cartridge, :from => rest_app.cartridges).first
285
+ amount = amount.match(/^(\d+)(GB)?$/i)
286
+ raise RHC::AdditionalStorageValueException if amount.nil?
287
+
288
+ # If the amount is specified, find the regex match and convert to a number
289
+ amount = amount[1].to_i
290
+ total_amount = rest_cartridge.additional_gear_storage
291
+
292
+ if operation == :add
293
+ total_amount += amount
294
+ elsif operation == :remove
295
+ if amount > total_amount && !options.force
296
+ raise RHC::AdditionalStorageRemoveException
297
+ else
298
+ total_amount = [total_amount - amount, 0].max
299
+ end
300
+ else
301
+ total_amount = amount
302
+ end
303
+
304
+ say "Set storage on cartridge ... "
305
+ cart = rest_cartridge.set_storage(:additional_gear_storage => total_amount)
306
+ success "set to #{total_amount}GB"
307
+ paragraph{ display_cart_storage_info cart }
308
+ end
309
+
310
+ 0
311
+ end
312
+
313
+ private
314
+ include RHC::CartridgeHelpers
315
+
316
+ def cartridge_action(cartridge, action, message=nil)
317
+ rest_app = find_app(:include => :cartridges)
318
+ rest_cartridge = check_cartridges(cartridge, :from => rest_app.cartridges).first
319
+ say message % [rest_cartridge.name] if message
320
+ result = rest_cartridge.send(action)
321
+ resp = [result, rest_cartridge, rest_app]
322
+ if message
323
+ success "done"
324
+ result.messages.each{ |s| paragraph{ say s } }
325
+ end
326
+ resp
327
+ end
328
+ end
329
+ end