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,34 @@
|
|
|
1
|
+
require 'rhc/commands/base'
|
|
2
|
+
require 'rhc/git_helpers'
|
|
3
|
+
|
|
4
|
+
module RHC::Commands
|
|
5
|
+
class GitClone < Base
|
|
6
|
+
summary "Clone and configure an application's repository locally"
|
|
7
|
+
description "This is a convenience wrapper for 'git clone' with the added",
|
|
8
|
+
"benefit of adding configuration data such as the application's",
|
|
9
|
+
"UUID to the local repository. It also automatically",
|
|
10
|
+
"figures out the Git url from the application name so you don't",
|
|
11
|
+
"have to look it up."
|
|
12
|
+
syntax "<app> [--namespace NAME]"
|
|
13
|
+
takes_application :argument => true
|
|
14
|
+
option ["-r", "--repo dir"], "Path to the Git repository (defaults to ./$app_name)"
|
|
15
|
+
alias_action 'app git-clone', :deprecated => true, :root_command => true
|
|
16
|
+
# TODO: Implement default values for arguments once ffranz has added context arguments
|
|
17
|
+
# argument :directory, "The name of a new directory to clone into", [], :default => nil
|
|
18
|
+
def run(app_name)
|
|
19
|
+
if has_git?
|
|
20
|
+
rest_app = find_app
|
|
21
|
+
dir = git_clone_application(rest_app)
|
|
22
|
+
success "Your application Git repository has been cloned to '#{system_path(dir)}'"
|
|
23
|
+
|
|
24
|
+
0
|
|
25
|
+
else
|
|
26
|
+
error "You do not have git installed. In order to fully interact with StartApp you will need to install and configure a git client."
|
|
27
|
+
2
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
include RHC::GitHelpers
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module RHC::Commands
|
|
2
|
+
class Logout < Base
|
|
3
|
+
suppress_wizard
|
|
4
|
+
|
|
5
|
+
summary "End the current session"
|
|
6
|
+
description <<-DESC
|
|
7
|
+
Logout ends your current session on the server and then removes
|
|
8
|
+
all of the local session files. If you are using multiple
|
|
9
|
+
servers and configurations this will remove all of your local
|
|
10
|
+
session files.
|
|
11
|
+
|
|
12
|
+
The --all option will terminate all authorizations on your
|
|
13
|
+
account. Any previously generated authorizations will be
|
|
14
|
+
deleted and external tools that integrate with your account
|
|
15
|
+
will no longer be able to log in.
|
|
16
|
+
DESC
|
|
17
|
+
option '--all', "Remove all authorizations on your account."
|
|
18
|
+
alias_action 'account logout', :root_command => true
|
|
19
|
+
def run
|
|
20
|
+
if options.all
|
|
21
|
+
rest_client.user # force authentication
|
|
22
|
+
say "Deleting all authorizations associated with your account ... "
|
|
23
|
+
begin
|
|
24
|
+
rest_client.delete_authorizations
|
|
25
|
+
success "done"
|
|
26
|
+
rescue RHC::Rest::AuthorizationsNotSupported
|
|
27
|
+
info "not supported"
|
|
28
|
+
end
|
|
29
|
+
elsif token_for_user
|
|
30
|
+
options.noprompt = true
|
|
31
|
+
say "Ending session on server ... "
|
|
32
|
+
begin
|
|
33
|
+
rest_client.delete_authorization(token_for_user)
|
|
34
|
+
success "deleted"
|
|
35
|
+
rescue RHC::Rest::AuthorizationsNotSupported
|
|
36
|
+
info "not supported"
|
|
37
|
+
rescue RHC::Rest::TokenExpiredOrInvalid
|
|
38
|
+
info "already closed"
|
|
39
|
+
rescue => e
|
|
40
|
+
debug_error(e)
|
|
41
|
+
warn e.message
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
0
|
|
46
|
+
ensure
|
|
47
|
+
token_store.clear
|
|
48
|
+
success "All local sessions removed."
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'rhc/commands/tail'
|
|
2
|
+
|
|
3
|
+
module RHC::Commands
|
|
4
|
+
class Logs < Tail
|
|
5
|
+
|
|
6
|
+
summary "Tail the logs of an application"
|
|
7
|
+
syntax "<application>"
|
|
8
|
+
takes_application :argument => true
|
|
9
|
+
option ["-o", "--opts options"], "Options to pass to the server-side (linux based) tail command (applicable to tail command only) (-f is implicit. See the linux tail man page full list of options.) (Ex: --opts '-n 100')"
|
|
10
|
+
option ["-f", "--files files"], "File glob relative to app (default <application_name>/logs/*) (optional)"
|
|
11
|
+
option ["-g", "--gear ID"], "Tail only a specific gear"
|
|
12
|
+
#option ["-c", "--cartridge name"], "Tail only a specific cartridge"
|
|
13
|
+
alias_action :"app tail", :root_command => true, :deprecated => true
|
|
14
|
+
def run(app_name)
|
|
15
|
+
super app_name
|
|
16
|
+
|
|
17
|
+
0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
require 'rhc/commands/base'
|
|
2
|
+
|
|
3
|
+
module RHC::Commands
|
|
4
|
+
class Member < Base
|
|
5
|
+
summary "Manage membership on domains"
|
|
6
|
+
syntax "<action>"
|
|
7
|
+
description <<-DESC
|
|
8
|
+
Teams of developers can collaborate on applications by adding people to
|
|
9
|
+
domains as members: each member has a role (admin, editor, or viewer),
|
|
10
|
+
and those roles determine what the user can do with the domain and the
|
|
11
|
+
applications contained within.
|
|
12
|
+
|
|
13
|
+
Roles:
|
|
14
|
+
|
|
15
|
+
view - able to see information about the domain and its apps, but not make any changes
|
|
16
|
+
edit - create, update, and delete applications, and has Git and SSH access
|
|
17
|
+
admin - can update membership of a domain
|
|
18
|
+
|
|
19
|
+
The default role granted to members when added is 'edit' - use the '--role'
|
|
20
|
+
argument to use another. When adding and removing members, you can use their
|
|
21
|
+
'login' value (typically their email or a short unique name for them) or their
|
|
22
|
+
'id'. Both login and ID are visible via the 'rhc account' command.
|
|
23
|
+
|
|
24
|
+
To see existing members of a domain or application, use:
|
|
25
|
+
|
|
26
|
+
rhc members -n <domain_name> [-a <app_name>]
|
|
27
|
+
|
|
28
|
+
To change the role for a user, simply call the add-member command with the new role. You
|
|
29
|
+
cannot change the role of the owner.
|
|
30
|
+
DESC
|
|
31
|
+
syntax "<action>"
|
|
32
|
+
default_action :help
|
|
33
|
+
|
|
34
|
+
summary "List members of a domain or application"
|
|
35
|
+
syntax "<domain_or_app_name> [-n DOMAIN_NAME] [-a APP_NAME]"
|
|
36
|
+
description <<-DESC
|
|
37
|
+
Show the existing members of a domain or application - you can pass the name
|
|
38
|
+
of your domain with '-n', the name of your application with '-a', or combine
|
|
39
|
+
them in the first argument to the command like:
|
|
40
|
+
|
|
41
|
+
rhc members <domain_name>/[<app_name>]
|
|
42
|
+
|
|
43
|
+
The owner is always listed first. To see the unique ID of members, pass
|
|
44
|
+
'--ids'.
|
|
45
|
+
DESC
|
|
46
|
+
option ['--ids'], "Display the IDs of each member", :optional => true
|
|
47
|
+
takes_application_or_domain :argument => true
|
|
48
|
+
alias_action :members, :root_command => true
|
|
49
|
+
def list(path)
|
|
50
|
+
target = find_app_or_domain(path)
|
|
51
|
+
members = target.members.sort_by{ |m| [m.owner? ? 0 : 1, m.role_weight, m.name] }
|
|
52
|
+
show_name = members.any?{ |m| m.name && m.name != m.login }
|
|
53
|
+
members.map! do |m|
|
|
54
|
+
[
|
|
55
|
+
((m.name || "") if show_name),
|
|
56
|
+
m.login || "",
|
|
57
|
+
m.owner? ? "#{m.role} (owner)" : m.role,
|
|
58
|
+
(m.id if options.ids)
|
|
59
|
+
].compact
|
|
60
|
+
end
|
|
61
|
+
say table(members, :header => [('Name' if show_name), 'Login', 'Role', ("ID" if options.ids)].compact)
|
|
62
|
+
|
|
63
|
+
0
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
summary "Add or update a member on a domain"
|
|
67
|
+
syntax "<login> [<login>...] [-n DOMAIN_NAME] [--role view|edit|admin] [--ids]"
|
|
68
|
+
description <<-DESC
|
|
69
|
+
Adds or updates members on a domain by passing one or more login
|
|
70
|
+
or ids for other people on OpenShift. The login and ID values for each
|
|
71
|
+
account are displayed in 'rhc account'. To change the role for a user, simply
|
|
72
|
+
call the add-member command with the new role. You cannot change the role of
|
|
73
|
+
the owner.
|
|
74
|
+
|
|
75
|
+
Roles
|
|
76
|
+
view - able to see information about the domain and its apps,
|
|
77
|
+
but not make any changes
|
|
78
|
+
edit - create, update, and delete applications, and has Git
|
|
79
|
+
and SSH access
|
|
80
|
+
admin - can update membership of a domain
|
|
81
|
+
|
|
82
|
+
The default role granted to members when added is 'edit' - use the '--role'
|
|
83
|
+
argument for 'view' or 'admin'.
|
|
84
|
+
|
|
85
|
+
Examples
|
|
86
|
+
rhc add-member sally joe -n mydomain
|
|
87
|
+
Gives the accounts with logins 'sally' and 'joe' edit access on mydomain
|
|
88
|
+
|
|
89
|
+
rhc add-member bob@example.com --role admin -n mydomain
|
|
90
|
+
Gives the account with login 'bob@example.com' admin access on mydomain
|
|
91
|
+
|
|
92
|
+
DESC
|
|
93
|
+
takes_domain
|
|
94
|
+
option ['--ids'], "Treat the arguments as a list of IDs", :optional => true
|
|
95
|
+
option ['-r', '--role ROLE'], "The role to give to each member - view, edit, or admin (default 'edit')", :type => Role, :optional => true
|
|
96
|
+
argument :members, "A list of members logins to add. Pass --ids to treat this as a list of IDs.", [], :type => :list
|
|
97
|
+
def add(members)
|
|
98
|
+
target = find_domain
|
|
99
|
+
role = options.role || 'edit'
|
|
100
|
+
raise ArgumentError, 'You must pass one or more logins or ids to this command' unless members.present?
|
|
101
|
+
say "Adding #{pluralize(members.length, role_name(role))} to #{target.class.model_name.downcase} ... "
|
|
102
|
+
target.update_members(changes_for(members, role))
|
|
103
|
+
success "done"
|
|
104
|
+
|
|
105
|
+
0
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
summary "Remove a member from a domain"
|
|
109
|
+
syntax "<login> [<login>...] [-n DOMAIN_NAME] [--ids]"
|
|
110
|
+
description <<-DESC
|
|
111
|
+
Remove members on a domain by passing one or more login or ids for each
|
|
112
|
+
member you wish to remove. View the list of existing members with
|
|
113
|
+
'rhc members <domain_name>'.
|
|
114
|
+
|
|
115
|
+
Pass '--all' to remove all but the owner from the domain.
|
|
116
|
+
DESC
|
|
117
|
+
takes_domain
|
|
118
|
+
option ['--ids'], "Treat the arguments as a list of IDs"
|
|
119
|
+
option ['--all'], "Remove all members from this domain."
|
|
120
|
+
argument :members, "Member logins to remove from the domain. Pass --ids to treat this as a list of IDs.", [], :type => :list
|
|
121
|
+
def remove(members)
|
|
122
|
+
target = find_domain
|
|
123
|
+
|
|
124
|
+
if options.all
|
|
125
|
+
say "Removing all members from #{target.class.model_name.downcase} ... "
|
|
126
|
+
target.delete_members
|
|
127
|
+
success "done"
|
|
128
|
+
|
|
129
|
+
else
|
|
130
|
+
raise ArgumentError, 'You must pass one or more logins or ids to this command' unless members.present?
|
|
131
|
+
say "Removing #{pluralize(members.length, 'member')} from #{target.class.model_name.downcase} ... "
|
|
132
|
+
target.update_members(changes_for(members, 'none'))
|
|
133
|
+
success "done"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
0
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
protected
|
|
140
|
+
def changes_for(members, role)
|
|
141
|
+
members.map do |m|
|
|
142
|
+
h = {:role => role}
|
|
143
|
+
h[options.ids ? :id : :login] = m
|
|
144
|
+
h
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
module RHC::Commands
|
|
4
|
+
class ForwardingSpec
|
|
5
|
+
include RHC::Helpers
|
|
6
|
+
include Enumerable
|
|
7
|
+
# class to represent how SSH port forwarding should be performed
|
|
8
|
+
attr_accessor :port_from
|
|
9
|
+
attr_reader :remote_host, :port_to, :host_from, :service
|
|
10
|
+
attr_writer :bound
|
|
11
|
+
|
|
12
|
+
def initialize(service, remote_host, port_to, port_from = nil)
|
|
13
|
+
@service = service
|
|
14
|
+
@remote_host = remote_host
|
|
15
|
+
@port_to = port_to
|
|
16
|
+
@host_from = '127.0.0.1'
|
|
17
|
+
@port_from = port_from || port_to # match ports if possible
|
|
18
|
+
@bound = false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_cmd_arg
|
|
22
|
+
# string to be used in a direct SSH command
|
|
23
|
+
"-L #{port_from}:#{remote_host}:#{port_to}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_fwd_args
|
|
27
|
+
# array of arguments to be passed to Net::SSH::Service::Forward#local
|
|
28
|
+
[port_from.to_i, remote_host, port_to.to_i]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def bound?
|
|
32
|
+
@bound
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# :nocov: These are for sorting. No need to test for coverage.
|
|
36
|
+
def <=>(other)
|
|
37
|
+
if bound? && !other.bound?
|
|
38
|
+
-1
|
|
39
|
+
elsif !bound? && other.bound?
|
|
40
|
+
1
|
|
41
|
+
else
|
|
42
|
+
order_by_attrs(other, :service, :remote_host, :port_from)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def order_by_attrs(other, *attrs)
|
|
47
|
+
# compare self and "other" by examining their "attrs" in order
|
|
48
|
+
# attrs should be an array of symbols to which self and "other"
|
|
49
|
+
# respond when sent.
|
|
50
|
+
while attribute = attrs.shift do
|
|
51
|
+
if self.send(attribute) != other.send(attribute)
|
|
52
|
+
return self.send(attribute) <=> other.send(attribute)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
0
|
|
56
|
+
end
|
|
57
|
+
# :nocov:
|
|
58
|
+
|
|
59
|
+
private :order_by_attrs
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class PortForward < Base
|
|
63
|
+
|
|
64
|
+
UP_TO_256 = /25[0-5]|2[0-4][0-9]|[01]?(?:[0-9][0-9]?)/
|
|
65
|
+
UP_TO_65535 = /6553[0-5]|655[0-2][0-9]|65[0-4][0-9][0-9]|6[0-4][0-9][0-9][0-9]|[0-5]?(?:[0-9][0-9]{0,3})/
|
|
66
|
+
# 'host' part is a bit lax; we rely on 'rhc-list-ports' to hand us a reasonable output
|
|
67
|
+
# about the host information, be it numeric or FQDN in IPv4 or IPv6.
|
|
68
|
+
HOST_AND_PORT = /(.+):(#{UP_TO_65535})\b/
|
|
69
|
+
|
|
70
|
+
summary "Forward remote ports to the workstation"
|
|
71
|
+
syntax "<application>"
|
|
72
|
+
takes_application :argument => true
|
|
73
|
+
option ["-g", "--gear ID"], "Gear ID you are port forwarding to (optional)"
|
|
74
|
+
def run(app)
|
|
75
|
+
rest_app = find_app
|
|
76
|
+
ssh_uri = URI.parse(options.gear ? rest_app.gear_ssh_url(options.gear) : rest_app.ssh_url)
|
|
77
|
+
|
|
78
|
+
say "Using #{ssh_uri}..." if options.debug
|
|
79
|
+
|
|
80
|
+
forwarding_specs = []
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
say "Checking available ports ... "
|
|
84
|
+
|
|
85
|
+
Net::SSH.start(ssh_uri.host, ssh_uri.user) do |ssh|
|
|
86
|
+
# If a specific gear is targeted, do not include remote (e.g. database) ports
|
|
87
|
+
list_ports_cmd = "rhc-list-ports#{options.gear ? ' --exclude-remote' : ''}"
|
|
88
|
+
ssh.exec! list_ports_cmd do |channel, stream, data|
|
|
89
|
+
if stream == :stderr
|
|
90
|
+
data.each_line do |line|
|
|
91
|
+
line.chomp!
|
|
92
|
+
# FIXME: This is really brittle; there must be a better way
|
|
93
|
+
# for the server to tell us that permission (what permission?)
|
|
94
|
+
# is denied.
|
|
95
|
+
raise RHC::PermissionDeniedException.new "Permission denied." if line =~ /permission denied/i
|
|
96
|
+
# ...and also which services are available for the application
|
|
97
|
+
# for us to forward ports for.
|
|
98
|
+
if line =~ /\A\s*(\S+) -> #{HOST_AND_PORT}\z/
|
|
99
|
+
debug fs = ForwardingSpec.new($1, $2, $3.to_i)
|
|
100
|
+
forwarding_specs << fs
|
|
101
|
+
else
|
|
102
|
+
debug line
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
if forwarding_specs.length == 0
|
|
110
|
+
# check if the gears have been stopped
|
|
111
|
+
if rest_app.gear_groups.all?{ |gg| gg.gears.all?{ |g| g["state"] == "stopped" } }
|
|
112
|
+
warn "none"
|
|
113
|
+
error "The application is stopped. Please restart the application and try again."
|
|
114
|
+
return 1
|
|
115
|
+
else
|
|
116
|
+
warn "none"
|
|
117
|
+
raise RHC::NoPortsToForwardException.new "There are no available ports to forward for this application. Your application may be stopped or idled."
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
success "done"
|
|
122
|
+
|
|
123
|
+
begin
|
|
124
|
+
Net::SSH.start(ssh_uri.host, ssh_uri.user) do |ssh|
|
|
125
|
+
say "Forwarding ports ..."
|
|
126
|
+
forwarding_specs.each do |fs|
|
|
127
|
+
given_up = nil
|
|
128
|
+
while !fs.bound? && !given_up
|
|
129
|
+
begin
|
|
130
|
+
args = fs.to_fwd_args
|
|
131
|
+
debug args.inspect
|
|
132
|
+
ssh.forward.local(*args)
|
|
133
|
+
fs.bound = true
|
|
134
|
+
rescue Errno::EADDRINUSE, Errno::EACCES => e
|
|
135
|
+
warn "#{e} while forwarding port #{fs.port_from}. Trying local port #{fs.port_from+1}"
|
|
136
|
+
fs.port_from += 1
|
|
137
|
+
rescue Timeout::Error, Errno::EADDRNOTAVAIL, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Net::SSH::AuthenticationFailed => e
|
|
138
|
+
given_up = true
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
bound_ports = forwarding_specs.select(&:bound?)
|
|
144
|
+
if bound_ports.length > 0
|
|
145
|
+
paragraph{ say "To connect to a service running on OpenShift, use the Local address" }
|
|
146
|
+
paragraph do
|
|
147
|
+
say table(
|
|
148
|
+
bound_ports.map do |fs|
|
|
149
|
+
[fs.service, "#{fs.host_from}:#{fs.port_from}", " => ", "#{fs.remote_host}:#{fs.port_to.to_s}"]
|
|
150
|
+
end,
|
|
151
|
+
:header => ["Service", "Local", " ", "OpenShift"]
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# for failed port forwarding attempts
|
|
157
|
+
failed_port_forwards = forwarding_specs.select { |fs| !fs.bound? }
|
|
158
|
+
if failed_port_forwards.length > 0
|
|
159
|
+
ssh_cmd_arg = failed_port_forwards.map { |fs| fs.to_cmd_arg }.join(" ")
|
|
160
|
+
ssh_cmd = "ssh -N #{ssh_cmd_arg} #{ssh_uri.user}@#{ssh_uri.host}"
|
|
161
|
+
warn "Error forwarding some port(s). You can try to forward manually by running:\n#{ssh_cmd}"
|
|
162
|
+
else
|
|
163
|
+
say "Press CTRL-C to terminate port forwarding"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
unless forwarding_specs.any?(&:bound?)
|
|
167
|
+
warn "No ports have been bound"
|
|
168
|
+
return
|
|
169
|
+
end
|
|
170
|
+
ssh.loop { true }
|
|
171
|
+
end
|
|
172
|
+
rescue Interrupt
|
|
173
|
+
say " Ending port forward"
|
|
174
|
+
return 0
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
rescue Timeout::Error, Errno::EADDRNOTAVAIL, Errno::EADDRINUSE, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Net::SSH::AuthenticationFailed => e
|
|
180
|
+
ssh_cmd = ["ssh","-N"]
|
|
181
|
+
unbound_fs = forwarding_specs.select { |fs| !fs.bound? }
|
|
182
|
+
ssh_cmd += unbound_fs.map { |fs| fs.to_cmd_arg }
|
|
183
|
+
ssh_cmd += ["#{ssh_uri.user}@#{ssh_uri.host}"]
|
|
184
|
+
raise RHC::PortForwardFailedException.new("#{e.message + "\n" if options.debug}Error trying to forward ports. You can try to forward manually by running:\n" + ssh_cmd.join(" "))
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
0
|
|
188
|
+
rescue RHC::Rest::ConnectionException => e
|
|
189
|
+
error "Connection to #{openshift_server} failed: #{e.message}"
|
|
190
|
+
1
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# mock for windows
|
|
196
|
+
if defined?(UNIXServer) != 'constant' or UNIXServer.class != Class then class UNIXServer; end; end
|
|
197
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'rhc/commands/app'
|
|
2
|
+
|
|
3
|
+
module RHC::Commands
|
|
4
|
+
class Reload < App
|
|
5
|
+
|
|
6
|
+
summary "Reload the application's configuration"
|
|
7
|
+
syntax "<app> [--namespace NAME]"
|
|
8
|
+
takes_application :argument => true
|
|
9
|
+
|
|
10
|
+
def run(app)
|
|
11
|
+
self.class.superclass.instance_method(:reload).bind(self).call app
|
|
12
|
+
|
|
13
|
+
0
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'rhc/commands/app'
|
|
2
|
+
|
|
3
|
+
module RHC::Commands
|
|
4
|
+
class Restart < App
|
|
5
|
+
|
|
6
|
+
summary "Restart the application"
|
|
7
|
+
syntax "<app> [--namespace NAME]"
|
|
8
|
+
takes_application :argument => true
|
|
9
|
+
|
|
10
|
+
def run(app)
|
|
11
|
+
self.class.superclass.instance_method(:restart).bind(self).call app
|
|
12
|
+
|
|
13
|
+
0
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'rhc/commands/base'
|
|
2
|
+
require 'rhc/scp_helpers'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module RHC::Commands
|
|
6
|
+
class Scp < Base
|
|
7
|
+
suppress_wizard
|
|
8
|
+
|
|
9
|
+
summary "SCP a file to or from your application"
|
|
10
|
+
description <<-DESC
|
|
11
|
+
Transfer files to and from your applications using SCP. This will transfer
|
|
12
|
+
files to and from your primary gear (the one with the Git repository and web
|
|
13
|
+
cartridge) by default.
|
|
14
|
+
|
|
15
|
+
Examples:
|
|
16
|
+
Uploading a file from your workding directory to your app-root/data directory
|
|
17
|
+
app scp myapp upload somefile.txt app-root/data
|
|
18
|
+
|
|
19
|
+
Downloading a file from your app-root/data directory to your working directory
|
|
20
|
+
app scp myapp download ./ app-root/data/somebigarchive.tar.gz
|
|
21
|
+
DESC
|
|
22
|
+
syntax "[<app> --] <action> <local_path> <remote_path>"
|
|
23
|
+
takes_application :argument => true
|
|
24
|
+
argument :action, "Transfer direction: upload|download", ["-t", "--transfer_direction upload|download"], :optional => false
|
|
25
|
+
argument :local_path, "Local filesystem path", ["-l", "--local_path file_path"], :optional => false
|
|
26
|
+
argument :remote_path, "Remote filesystem path", ["-r", "--remote_path file_path"], :optional => false
|
|
27
|
+
alias_action 'app scp', :root_command => true
|
|
28
|
+
def run(_, action, local_path, remote_path)
|
|
29
|
+
rest_app = find_app
|
|
30
|
+
ssh_opts = rest_app.ssh_url.gsub("ssh://","").split("@")
|
|
31
|
+
|
|
32
|
+
raise RHC::ArgumentNotValid.new("'#{action}' is not a valid argument for this command. Please use upload or download.") unless action == 'download' || action == 'upload'
|
|
33
|
+
raise RHC::FileOrPathNotFound.new("Local file, file_path, or directory could not be found.") unless File.exist?(local_path)
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
start_time = Time.now
|
|
37
|
+
Net::SCP.send("#{action}!".to_sym, ssh_opts[1], ssh_opts[0], (action == 'upload' ? local_path : remote_path), (action == 'upload' ? remote_path : local_path)) do |ch, name, sent, total|
|
|
38
|
+
#:nocov:
|
|
39
|
+
$stderr.print "\r #{action}ing #{name}: #{((sent.to_f/total.to_f)*100).to_i}% complete. #{sent}/#{total} bytes transferred " + (sent == total ? "in #{Time.now - start_time} seconds \n" : "")
|
|
40
|
+
#:nocov:
|
|
41
|
+
end
|
|
42
|
+
rescue Errno::ECONNREFUSED
|
|
43
|
+
raise RHC::SSHConnectionRefused.new(ssh_opts[0], ssh_opts[1])
|
|
44
|
+
rescue SocketError => e
|
|
45
|
+
raise RHC::ConnectionFailed, "The connection to #{ssh_opts[1]} failed: #{e.message}"
|
|
46
|
+
rescue Net::SCP::Error => e
|
|
47
|
+
raise RHC::RemoteFileOrPathNotFound.new("Remote file, file_path, or directory could not be found.")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
protected
|
|
52
|
+
include RHC::SCPHelpers
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module RHC::Commands
|
|
2
|
+
class Server < Base
|
|
3
|
+
suppress_wizard
|
|
4
|
+
|
|
5
|
+
summary "Display information about the status of the OpenShift service"
|
|
6
|
+
description <<-DESC
|
|
7
|
+
Retrieves any open issues or notices about the operation of the
|
|
8
|
+
OpenShift service and displays them in the order they were opened.
|
|
9
|
+
|
|
10
|
+
When connected to an OpenShift Enterprise server, will only display
|
|
11
|
+
the version of the API that it is connecting to.
|
|
12
|
+
DESC
|
|
13
|
+
def run
|
|
14
|
+
say "Connected to #{openshift_server}"
|
|
15
|
+
|
|
16
|
+
if openshift_online_server?
|
|
17
|
+
#status = decode_json(get("#{openshift_url}/app/status/status.json").body)
|
|
18
|
+
status = rest_client.request(:method => :get, :url => "#{openshift_url}/app/status/status.json", :lazy_auth => true){ |res| decode_json(res.content) }
|
|
19
|
+
open = status['open']
|
|
20
|
+
|
|
21
|
+
(success 'All systems running fine' and return 0) if open.blank?
|
|
22
|
+
|
|
23
|
+
open.each do |i|
|
|
24
|
+
i = i['issue']
|
|
25
|
+
say color("%-3s %s" % ["##{i['id']}", i['title']], :bold)
|
|
26
|
+
items = i['updates'].map{ |u| [u['description'], date(u['created_at'])] }
|
|
27
|
+
items.unshift ['Opened', date(i['created_at'])]
|
|
28
|
+
table(items, :align => [nil,:right], :join => ' ').each{ |s| say " #{s}" }
|
|
29
|
+
end
|
|
30
|
+
say "\n"
|
|
31
|
+
warn pluralize(open.length, "open issue")
|
|
32
|
+
|
|
33
|
+
open.length #exit with the count of open items
|
|
34
|
+
else
|
|
35
|
+
success "Using API version #{rest_client.api_version_negotiated}"
|
|
36
|
+
0
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'rhc/commands/base'
|
|
2
|
+
require 'rhc/wizard'
|
|
3
|
+
require 'rhc/config'
|
|
4
|
+
|
|
5
|
+
module RHC::Commands
|
|
6
|
+
class Setup < Base
|
|
7
|
+
suppress_wizard
|
|
8
|
+
|
|
9
|
+
summary "Connects to StartApp and sets up your keys and domain"
|
|
10
|
+
description <<-DESC
|
|
11
|
+
Connects to an StartApp server to get you started. Will help you
|
|
12
|
+
configure your SSH keys, set up a domain, and check for any potential
|
|
13
|
+
problems with Git or SSH.
|
|
14
|
+
|
|
15
|
+
Any options you pass to the setup command will be stored in a
|
|
16
|
+
.openshift/express.conf file in your home directory. If you run
|
|
17
|
+
setup at a later time, any previous configuration will be reused.
|
|
18
|
+
|
|
19
|
+
Pass the --clean option to ignore your saved configuration and only
|
|
20
|
+
use options you pass on the command line. Pass --config FILE to use
|
|
21
|
+
default values from another config (the values will still be written
|
|
22
|
+
to .startapp/express.conf).
|
|
23
|
+
|
|
24
|
+
If the server supports authorization tokens, you may pass the
|
|
25
|
+
--create-token option to instruct the wizard to generate a key for you.
|
|
26
|
+
|
|
27
|
+
If you would like to enable tab-completion in Bash shells, pass
|
|
28
|
+
--autocomplete for more information.
|
|
29
|
+
DESC
|
|
30
|
+
option ["--server NAME"], "Hostname of an OpenShift server", :default => :server_context, :required => true
|
|
31
|
+
option ['--clean'], "Ignore any saved configuration options"
|
|
32
|
+
option ['--[no-]create-token'], "Create an authorization token for this server"
|
|
33
|
+
option ['--autocomplete'], "Instructions for enabling tab-completion"
|
|
34
|
+
def run
|
|
35
|
+
if options.autocomplete
|
|
36
|
+
src = File.join(File.join(Gem.loaded_specs['app'].full_gem_path, "autocomplete"), "rhc_bash")
|
|
37
|
+
dest = File.join(RHC::Config.home_conf_dir, "bash_autocomplete")
|
|
38
|
+
|
|
39
|
+
FileUtils.mkdir_p(RHC::Config.home_conf_dir)
|
|
40
|
+
FileUtils.cp(src, dest)
|
|
41
|
+
|
|
42
|
+
say <<-LINE.strip_heredoc
|
|
43
|
+
To enable tab-completion for `app` under Bash shells, add the following command to
|
|
44
|
+
your .bashrc or .bash_profile file:
|
|
45
|
+
|
|
46
|
+
. #{dest}
|
|
47
|
+
|
|
48
|
+
Save your shell and then restart. Type "app" and then hit the TAB key twice to
|
|
49
|
+
trigger completion of your command.
|
|
50
|
+
|
|
51
|
+
Tab-completion is not available in the Windows terminal.
|
|
52
|
+
LINE
|
|
53
|
+
return 0
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
raise OptionParser::InvalidOption, "Setup can not be run with the --noprompt option" if options.noprompt
|
|
57
|
+
RHC::RerunWizard.new(config, options).run ? 0 : 1
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|