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.
- checksums.yaml +7 -0
- data/COPYRIGHT +1 -0
- data/LICENSE +11 -0
- data/README.md +95 -0
- data/Rakefile +6 -0
- data/autocomplete/rhc_bash +1672 -0
- data/bin/app +37 -0
- data/conf/express.conf +8 -0
- data/features/assets/deploy.tar.gz +0 -0
- data/features/core_feature.rb +191 -0
- data/features/deployments_feature.rb +129 -0
- data/features/domains_feature.rb +58 -0
- data/features/keys_feature.rb +37 -0
- data/features/members_feature.rb +166 -0
- data/lib/rhc/auth/basic.rb +64 -0
- data/lib/rhc/auth/token.rb +102 -0
- data/lib/rhc/auth/token_store.rb +53 -0
- data/lib/rhc/auth.rb +5 -0
- data/lib/rhc/autocomplete.rb +66 -0
- data/lib/rhc/autocomplete_templates/bash.erb +39 -0
- data/lib/rhc/cartridge_helpers.rb +118 -0
- data/lib/rhc/cli.rb +40 -0
- data/lib/rhc/command_runner.rb +185 -0
- data/lib/rhc/commands/account.rb +25 -0
- data/lib/rhc/commands/alias.rb +124 -0
- data/lib/rhc/commands/app.rb +726 -0
- data/lib/rhc/commands/apps.rb +20 -0
- data/lib/rhc/commands/authorization.rb +115 -0
- data/lib/rhc/commands/base.rb +174 -0
- data/lib/rhc/commands/cartridge.rb +329 -0
- data/lib/rhc/commands/clone.rb +66 -0
- data/lib/rhc/commands/configure.rb +20 -0
- data/lib/rhc/commands/create.rb +100 -0
- data/lib/rhc/commands/delete.rb +19 -0
- data/lib/rhc/commands/deploy.rb +32 -0
- data/lib/rhc/commands/deployment.rb +82 -0
- data/lib/rhc/commands/domain.rb +172 -0
- data/lib/rhc/commands/env.rb +142 -0
- data/lib/rhc/commands/force_stop.rb +17 -0
- data/lib/rhc/commands/git_clone.rb +34 -0
- data/lib/rhc/commands/logout.rb +51 -0
- data/lib/rhc/commands/logs.rb +21 -0
- data/lib/rhc/commands/member.rb +148 -0
- data/lib/rhc/commands/port_forward.rb +197 -0
- data/lib/rhc/commands/reload.rb +17 -0
- data/lib/rhc/commands/restart.rb +17 -0
- data/lib/rhc/commands/scp.rb +54 -0
- data/lib/rhc/commands/server.rb +40 -0
- data/lib/rhc/commands/setup.rb +60 -0
- data/lib/rhc/commands/show.rb +43 -0
- data/lib/rhc/commands/snapshot.rb +137 -0
- data/lib/rhc/commands/ssh.rb +51 -0
- data/lib/rhc/commands/sshkey.rb +97 -0
- data/lib/rhc/commands/start.rb +17 -0
- data/lib/rhc/commands/stop.rb +17 -0
- data/lib/rhc/commands/tail.rb +47 -0
- data/lib/rhc/commands/threaddump.rb +14 -0
- data/lib/rhc/commands/tidy.rb +17 -0
- data/lib/rhc/commands.rb +396 -0
- data/lib/rhc/config.rb +321 -0
- data/lib/rhc/context_helper.rb +121 -0
- data/lib/rhc/core_ext.rb +202 -0
- data/lib/rhc/coverage_helper.rb +33 -0
- data/lib/rhc/deployment_helpers.rb +111 -0
- data/lib/rhc/exceptions.rb +256 -0
- data/lib/rhc/git_helpers.rb +106 -0
- data/lib/rhc/help_formatter.rb +55 -0
- data/lib/rhc/helpers.rb +481 -0
- data/lib/rhc/highline_extensions.rb +479 -0
- data/lib/rhc/json.rb +51 -0
- data/lib/rhc/output_helpers.rb +260 -0
- data/lib/rhc/rest/activation.rb +11 -0
- data/lib/rhc/rest/alias.rb +42 -0
- data/lib/rhc/rest/api.rb +87 -0
- data/lib/rhc/rest/application.rb +348 -0
- data/lib/rhc/rest/attributes.rb +36 -0
- data/lib/rhc/rest/authorization.rb +8 -0
- data/lib/rhc/rest/base.rb +79 -0
- data/lib/rhc/rest/cartridge.rb +162 -0
- data/lib/rhc/rest/client.rb +650 -0
- data/lib/rhc/rest/deployment.rb +18 -0
- data/lib/rhc/rest/domain.rb +98 -0
- data/lib/rhc/rest/environment_variable.rb +15 -0
- data/lib/rhc/rest/gear_group.rb +16 -0
- data/lib/rhc/rest/httpclient.rb +145 -0
- data/lib/rhc/rest/key.rb +44 -0
- data/lib/rhc/rest/membership.rb +105 -0
- data/lib/rhc/rest/mock.rb +1042 -0
- data/lib/rhc/rest/user.rb +32 -0
- data/lib/rhc/rest.rb +148 -0
- data/lib/rhc/scp_helpers.rb +27 -0
- data/lib/rhc/ssh_helpers.rb +380 -0
- data/lib/rhc/tar_gz.rb +51 -0
- data/lib/rhc/usage_templates/command_help.erb +51 -0
- data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
- data/lib/rhc/usage_templates/help.erb +61 -0
- data/lib/rhc/usage_templates/missing_help.erb +1 -0
- data/lib/rhc/usage_templates/options_help.erb +12 -0
- data/lib/rhc/vendor/okjson.rb +600 -0
- data/lib/rhc/vendor/parseconfig.rb +178 -0
- data/lib/rhc/vendor/sshkey.rb +253 -0
- data/lib/rhc/vendor/zliby.rb +628 -0
- data/lib/rhc/version.rb +5 -0
- data/lib/rhc/wizard.rb +637 -0
- data/lib/rhc.rb +34 -0
- data/spec/coverage_helper.rb +82 -0
- data/spec/direct_execution_helper.rb +339 -0
- data/spec/keys/example.pem +23 -0
- data/spec/keys/example_private.pem +27 -0
- data/spec/keys/server.pem +19 -0
- data/spec/rest_spec_helper.rb +31 -0
- data/spec/rhc/assets/cert.crt +22 -0
- data/spec/rhc/assets/cert_key_rsa +27 -0
- data/spec/rhc/assets/empty.txt +0 -0
- data/spec/rhc/assets/env_vars.txt +7 -0
- data/spec/rhc/assets/env_vars_2.txt +1 -0
- data/spec/rhc/assets/foo.txt +1 -0
- data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
- data/spec/rhc/assets/targz_sample.tar.gz +0 -0
- data/spec/rhc/auth_spec.rb +442 -0
- data/spec/rhc/cli_spec.rb +186 -0
- data/spec/rhc/command_spec.rb +435 -0
- data/spec/rhc/commands/account_spec.rb +42 -0
- data/spec/rhc/commands/alias_spec.rb +333 -0
- data/spec/rhc/commands/app_spec.rb +777 -0
- data/spec/rhc/commands/apps_spec.rb +39 -0
- data/spec/rhc/commands/authorization_spec.rb +157 -0
- data/spec/rhc/commands/cartridge_spec.rb +665 -0
- data/spec/rhc/commands/clone_spec.rb +41 -0
- data/spec/rhc/commands/deployment_spec.rb +327 -0
- data/spec/rhc/commands/domain_spec.rb +401 -0
- data/spec/rhc/commands/env_spec.rb +493 -0
- data/spec/rhc/commands/git_clone_spec.rb +102 -0
- data/spec/rhc/commands/logout_spec.rb +86 -0
- data/spec/rhc/commands/member_spec.rb +247 -0
- data/spec/rhc/commands/port_forward_spec.rb +217 -0
- data/spec/rhc/commands/scp_spec.rb +77 -0
- data/spec/rhc/commands/server_spec.rb +69 -0
- data/spec/rhc/commands/setup_spec.rb +118 -0
- data/spec/rhc/commands/snapshot_spec.rb +179 -0
- data/spec/rhc/commands/ssh_spec.rb +163 -0
- data/spec/rhc/commands/sshkey_spec.rb +188 -0
- data/spec/rhc/commands/tail_spec.rb +81 -0
- data/spec/rhc/commands/threaddump_spec.rb +84 -0
- data/spec/rhc/config_spec.rb +407 -0
- data/spec/rhc/helpers_spec.rb +531 -0
- data/spec/rhc/highline_extensions_spec.rb +314 -0
- data/spec/rhc/json_spec.rb +30 -0
- data/spec/rhc/rest_application_spec.rb +258 -0
- data/spec/rhc/rest_client_spec.rb +752 -0
- data/spec/rhc/rest_spec.rb +740 -0
- data/spec/rhc/targz_spec.rb +55 -0
- data/spec/rhc/wizard_spec.rb +756 -0
- data/spec/spec_helper.rb +575 -0
- data/spec/wizard_spec_helper.rb +330 -0
- 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
|