startapp 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,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