startapp 0.1.6

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