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,32 @@
1
+ require 'ostruct'
2
+
3
+ module RHC
4
+ module Rest
5
+ class User < Base
6
+ define_attr :id, :login, :plan_id, :max_gears, :consumed_gears, :max_domains
7
+
8
+ def add_key(name, content, type)
9
+ debug "Add key #{name} of type #{type} for user #{login}"
10
+ rest_method "ADD_KEY", :name => name, :type => type, :content => content
11
+ end
12
+
13
+ def keys
14
+ debug "Getting all keys for user #{login}"
15
+ rest_method "LIST_KEYS"
16
+ end
17
+
18
+ #Find Key by name
19
+ def find_key(name)
20
+ keys.detect { |key| key.name == name }
21
+ end
22
+
23
+ def max_domains
24
+ attributes['max_domains'] || 1
25
+ end
26
+
27
+ def capabilities
28
+ @capabilities ||= OpenStruct.new attribute('capabilities')
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/rhc/rest.rb ADDED
@@ -0,0 +1,148 @@
1
+ module RHC
2
+ module Rest
3
+
4
+ autoload :Base, 'rhc/rest/base'
5
+ autoload :Attributes, 'rhc/rest/attributes'
6
+
7
+ autoload :HTTPClient, 'rhc/rest/httpclient'
8
+
9
+ autoload :Alias, 'rhc/rest/alias'
10
+ autoload :Api, 'rhc/rest/api'
11
+ autoload :Application, 'rhc/rest/application'
12
+ autoload :Authorization, 'rhc/rest/authorization'
13
+ autoload :Cartridge, 'rhc/rest/cartridge'
14
+ autoload :Client, 'rhc/rest/client'
15
+ autoload :Deployment, 'rhc/rest/deployment'
16
+ autoload :Domain, 'rhc/rest/domain'
17
+ autoload :EnvironmentVariable, 'rhc/rest/environment_variable'
18
+ autoload :GearGroup, 'rhc/rest/gear_group'
19
+ autoload :Key, 'rhc/rest/key'
20
+ autoload :Membership, 'rhc/rest/membership'
21
+ autoload :User, 'rhc/rest/user'
22
+
23
+ class Exception < RuntimeError
24
+ attr_reader :code
25
+ def initialize(message=nil, code=1)
26
+ super(message)
27
+ @code = (Integer(code) rescue nil)
28
+ end
29
+ end
30
+
31
+ #Exceptions thrown in case of an HTTP 5xx is received.
32
+ class ServerErrorException < Exception; end
33
+
34
+ #Exceptions thrown in case of an HTTP 503 is received.
35
+ #
36
+ #503 Service Unavailable
37
+ #
38
+ #The server is currently unable to handle the request due to a temporary
39
+ #overloading or maintenance of the server. The implication is that this
40
+ #is a temporary condition which will be alleviated after some delay.
41
+ class ServiceUnavailableException < ServerErrorException; end
42
+
43
+ #Exceptions thrown in case of an HTTP 4xx is received with the exception
44
+ #of 401, 403, 403 and 422 where a more sepcific exception is thrown
45
+ #
46
+ #HTTP Error Codes 4xx
47
+ #
48
+ #The 4xx class of status code is intended for cases in which the client
49
+ #seems to have errored.
50
+ class ClientErrorException < Exception; end
51
+
52
+ #Exceptions thrown in case of an HTTP 404 is received.
53
+ #
54
+ #404 Not Found
55
+ #
56
+ #The server has not found anything matching the Request-URI or the
57
+ #requested resource does not exist
58
+ class ResourceNotFoundException < ClientErrorException; end
59
+ class ApiEndpointNotFound < ResourceNotFoundException; end
60
+
61
+ # 404 errors for specific resource types
62
+ class DomainNotFoundException < ResourceNotFoundException
63
+ def initialize(msg)
64
+ super(msg,127)
65
+ end
66
+ end
67
+ class ApplicationNotFoundException < ResourceNotFoundException
68
+ def initialize(msg)
69
+ super(msg,101)
70
+ end
71
+ end
72
+
73
+ #Exceptions thrown in case of an HTTP 422 is received.
74
+ class ValidationException < ClientErrorException
75
+ attr_reader :field
76
+ def initialize(message, field=nil, error_code=1)
77
+ super(message, error_code)
78
+ @field = field
79
+ end
80
+ end
81
+
82
+ #Exceptions thrown in case of an HTTP 403 is received.
83
+ #
84
+ #403 Forbidden
85
+ #
86
+ #The server understood the request, but is refusing to fulfill it.
87
+ #Authorization will not help and the request SHOULD NOT be repeated.
88
+ class RequestDeniedException < ClientErrorException; end
89
+
90
+ #Exceptions thrown in case of an HTTP 401 is received.
91
+ #
92
+ #401 Unauthorized
93
+ #
94
+ #The request requires user authentication. If the request already
95
+ #included Authorization credentials, then the 401 response indicates
96
+ #that authorization has been refused for those credentials.
97
+ class UnAuthorizedException < ClientErrorException; end
98
+ class TokenExpiredOrInvalid < UnAuthorizedException; end
99
+
100
+ # DEPRECATED Unreachable host, SSL Exception
101
+ class ResourceAccessException < Exception; end
102
+
103
+ #I/O Exceptions Connection timeouts, etc
104
+ class ConnectionException < Exception; end
105
+ class TimeoutException < ConnectionException
106
+ def initialize(message, nested=nil)
107
+ super(message)
108
+ @nested = nested
109
+ end
110
+
111
+ def on_receive?
112
+ @nested.is_a? HTTPClient::ReceiveTimeoutError
113
+ end
114
+ def on_connect?
115
+ @nested.is_a? HTTPClient::ConnectTimeoutError
116
+ end
117
+ def on_send?
118
+ @nested.is_a? HTTPClient::SendTimeoutError
119
+ end
120
+ end
121
+
122
+ class SSLConnectionFailed < ConnectionException
123
+ attr_reader :reason
124
+ def initialize(reason, message)
125
+ super message
126
+ @reason = reason
127
+ end
128
+ end
129
+ class CertificateVerificationFailed < SSLConnectionFailed; end
130
+ class SelfSignedCertificate < CertificateVerificationFailed; end
131
+
132
+ class SSLVersionRejected < SSLConnectionFailed; end
133
+
134
+ class MultipleCartridgeCreationNotSupported < Exception; end
135
+
136
+ class DownloadingCartridgesNotSupported < Exception; end
137
+
138
+ class InitialGitUrlNotSupported < Exception; end
139
+
140
+ class SslCertificatesNotSupported < Exception; end
141
+
142
+ class AuthorizationsNotSupported < Exception
143
+ def initialize(message="The server does not support setting, retrieving, or authenticating with authorization tokens.")
144
+ super(message, 1)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,27 @@
1
+ ###
2
+ # ssh_key_helpers.rb - methods to help manipulate ssh keys
3
+ #
4
+ # Copyright 2012 Red Hat, Inc. and/or its affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'net/ssh'
19
+ require 'net/scp'
20
+ require 'rhc/ssh_helpers'
21
+ require 'rhc/vendor/sshkey'
22
+
23
+ module RHC
24
+ module SCPHelpers
25
+ include SSHHelpers
26
+ end
27
+ end
@@ -0,0 +1,380 @@
1
+ ###
2
+ # ssh_key_helpers.rb - methods to help manipulate ssh keys
3
+ #
4
+ # Copyright 2012 Red Hat, Inc. and/or its affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'net/ssh'
19
+ require 'rhc/vendor/sshkey'
20
+ require 'httpclient'
21
+
22
+ module RHC
23
+ module SSHHelpers
24
+
25
+ class MultipleGearTask
26
+ def initialize(command, over, opts={})
27
+ requires_ssh_multi!
28
+
29
+ @command = command
30
+ @over = over
31
+ @opts = opts
32
+ end
33
+
34
+ def run(&block)
35
+ out = nil
36
+
37
+ Net::SSH::Multi.start(
38
+ :concurrent_connections => @opts[:limit],
39
+ :on_error => lambda{ |server| $stderr.puts RHC::Helpers.color("Unable to connect to gear #{server}", :red) }
40
+ ) do |session|
41
+
42
+ @over.each do |item|
43
+ case item
44
+ when RHC::Rest::GearGroup
45
+ item.gears.each do |gear|
46
+ session.use ssh_host_for(gear), :properties => {:gear => gear, :group => item}
47
+ end
48
+ #when RHC::Rest::Gear
49
+ # session.use ssh_host_for(item), :properties => {:gear => item}
50
+ #end
51
+ else
52
+ raise "Cannot establish an SSH session to this type"
53
+ end
54
+ end
55
+ session.exec @command, &(
56
+ case
57
+ when @opts[:raw]
58
+ lambda { |ch, dest, data|
59
+ (dest == :stdout ? $stdout : $stderr).puts data
60
+ }
61
+ when @opts[:as] == :table
62
+ out = []
63
+ lambda { |ch, dest, data|
64
+ label = label_for(ch)
65
+ data.chomp.each_line do |line|
66
+ row = out.find{ |row| row[0] == label } || (out << [label, []])[-1]
67
+ row[1] << line
68
+ end
69
+ }
70
+ when @opts[:as] == :gear
71
+ lambda { |ch, dest, data| (ch.connection.properties[:gear]['data'] ||= "") << data }
72
+ else
73
+ width = 0
74
+ lambda { |ch, dest, data|
75
+ label = label_for(ch)
76
+ io = dest == :stdout ? $stdout : $stderr
77
+ data.chomp!
78
+
79
+ if data.each_line.to_a.count < 2
80
+ io.puts "[#{label}] #{data}"
81
+ elsif @opts[:always_prefix]
82
+ data.each_line do |line|
83
+ io.puts "[#{label}] #{line}"
84
+ end
85
+ else
86
+ io.puts "=== #{label}"
87
+ io.puts data
88
+ end
89
+ }
90
+ end)
91
+ session.loop
92
+ end
93
+
94
+ if block_given? && !@opts[:raw]
95
+ case
96
+ when @opts[:as] == :gear
97
+ out = []
98
+ @over.each do |item|
99
+ case item
100
+ when RHC::Rest::GearGroup then item.gears.each{ |gear| out << yield(gear, gear['data'], item) }
101
+ #when RHC::Rest::Gear then out << yield(gear, gear['data'], nil)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ out
108
+ end
109
+ protected
110
+ def ssh_host_for(gear)
111
+ RHC::Helpers.ssh_string(gear['ssh_url']) or raise NoPerGearOperations
112
+ end
113
+
114
+ def label_for(channel)
115
+ channel.properties[:label] ||=
116
+ begin
117
+ group = channel.connection.properties[:group]
118
+ "#{key_for(channel)} #{group.cartridges.map{ |c| c['name'] }.join('+')}"
119
+ end
120
+ end
121
+
122
+ def key_for(channel)
123
+ channel.connection.properties[:gear]['id']
124
+ end
125
+
126
+ def requires_ssh_multi!
127
+ begin
128
+ require 'net/ssh/multi'
129
+ rescue LoadError
130
+ raise RHC::OperationNotSupportedException, "You must install Net::SSH::Multi to use the --gears option. Most systems: 'gem install net-ssh-multi'"
131
+ end
132
+ end
133
+ end
134
+
135
+ def run_on_gears(command, gears, opts={}, &block)
136
+ debug "Executing #{command} on each of #{gears.inspect}"
137
+ MultipleGearTask.new(command, gears, {:limit => options.limit, :always_prefix => options.always_prefix, :raw => options.raw}.merge(opts)).run(&block)
138
+ end
139
+
140
+ def table_from_gears(command, groups, opts={}, &block)
141
+ cells = run_on_gears(command, groups, {:as => :table}.merge(opts), &block)
142
+ cells.each{ |r| r.concat(r.pop.first.split(opts[:split_cells_on])) } if !block_given? && opts[:split_cells_on]
143
+ say table cells, opts unless options.raw
144
+ end
145
+
146
+ def ssh_command_for_op(operation)
147
+ #case operation
148
+ raise RHC::OperationNotSupportedException, "The operation #{operation} is not supported."
149
+ #end
150
+ end
151
+
152
+ # Public: Run ssh command on remote host
153
+ #
154
+ # host - The String of the remote hostname to ssh to.
155
+ # username - The String username of the remote user to ssh as.
156
+ # command - The String command to run on the remote host.
157
+ # compression - Use compression in ssh, set to false if sending files.
158
+ # request_pty - Request for pty, set to false when pipe a file.
159
+ # block - Will yield this block and send the channel if provided.
160
+ #
161
+ # Examples
162
+ #
163
+ # ssh_ruby('myapp-t.rhcloud.com',
164
+ # '109745632b514e9590aa802ec015b074',
165
+ # 'rhcsh tail -f $OPENSHIFT_LOG_DIR/*"')
166
+ # # => true
167
+ #
168
+ # Returns true on success
169
+ def ssh_ruby(host, username, command, compression=false, request_pty=false, &block)
170
+ debug "Opening Net::SSH connection to #{host}, #{username}, #{command}"
171
+ exit_status = 0
172
+ options = {:compression => compression}
173
+ options[:verbose] = :debug if debug?
174
+ Net::SSH.start(host, username, options) do |session|
175
+ #:nocov:
176
+ channel = session.open_channel do |channel|
177
+ if request_pty
178
+ channel.request_pty do |ch, success|
179
+ say "pty could not be obtained" unless success
180
+ end
181
+ end
182
+ channel.exec(command) do |ch, success|
183
+ channel.on_data do |ch, data|
184
+ print data
185
+ end
186
+ channel.on_extended_data do |ch, type, data|
187
+ print data
188
+ end
189
+ channel.on_close do |ch|
190
+ debug "Terminating ... "
191
+ end
192
+ channel.on_request("exit-status") do |ch, data|
193
+ exit_status = data.read_long
194
+ end
195
+ yield channel if block_given?
196
+ channel.eof!
197
+ end
198
+ end
199
+ session.loop
200
+ #:nocov:
201
+ end
202
+ raise RHC::SSHCommandFailed.new(exit_status) if exit_status != 0
203
+ rescue Errno::ECONNREFUSED => e
204
+ debug_error e
205
+ raise RHC::SSHConnectionRefused.new(host, username)
206
+ rescue Net::SSH::AuthenticationFailed => e
207
+ debug_error e
208
+ raise RHC::SSHAuthenticationFailed.new(host, username)
209
+ rescue SocketError => e
210
+ debug_error e
211
+ raise RHC::ConnectionFailed, "The connection to #{host} failed: #{e.message}"
212
+ end
213
+
214
+
215
+ # Public: Run ssh command on remote host and pipe the specified
216
+ # file contents to the command input
217
+ #
218
+ # host - The String of the remote hostname to ssh to.
219
+ # username - The String username of the remote user to ssh as.
220
+ # command - The String command to run on the remote host.
221
+ # filename - The String path to file to send.
222
+ #
223
+ def ssh_send_file_ruby(host, username, command, filename)
224
+ filename = File.expand_path(filename)
225
+ ssh_ruby(host, username, command) do |channel|
226
+ File.open(filename, 'rb') do |file|
227
+ file.chunk(1024) do |chunk|
228
+ channel.send_data chunk
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ # Public: Run ssh command on remote host and pipe the specified
235
+ # url contents to the command input
236
+ #
237
+ # host - The String of the remote hostname to ssh to.
238
+ # username - The String username of the remote user to ssh as.
239
+ # command - The String command to run on the remote host.
240
+ # content_url - The url with the content to pipe to command.
241
+ #
242
+ def ssh_send_url_ruby(host, username, command, content_url)
243
+ content_url = URI.parse(URI.encode(content_url.to_s))
244
+ ssh_ruby(host, username, command) do |channel|
245
+ HTTPClient.new.get_content(content_url) do |chunk|
246
+ channel.send_data chunk
247
+ end
248
+ end
249
+ end
250
+
251
+ # Public: Generate an SSH key and store it in ~/.ssh/id_rsa
252
+ #
253
+ # type - The String type RSA or DSS.
254
+ # bits - The Integer value for number of bits.
255
+ # comment - The String comment for the key
256
+ #
257
+ # Examples
258
+ #
259
+ # generate_ssh_key_ruby
260
+ # # => /home/user/.ssh/id_rsa.pub
261
+ #
262
+ # Returns nil on failure or public key location as a String on success
263
+ def generate_ssh_key_ruby(type="RSA", bits = 2048, comment = "OpenShift-Key")
264
+ key = RHC::Vendor::SSHKey.generate(:type => type,
265
+ :bits => bits,
266
+ :comment => comment)
267
+ ssh_dir = RHC::Config.ssh_dir
268
+ priv_key = RHC::Config.ssh_priv_key_file_path
269
+ pub_key = RHC::Config.ssh_pub_key_file_path
270
+
271
+ if File.exists?(priv_key)
272
+ say "SSH key already exists: #{priv_key}. Reusing..."
273
+ return nil
274
+ else
275
+ unless File.exists?(ssh_dir)
276
+ FileUtils.mkdir_p(ssh_dir)
277
+ File.chmod(0700, ssh_dir)
278
+ end
279
+ File.open(priv_key, 'w') {|f| f.write(key.private_key)}
280
+ File.chmod(0600, priv_key)
281
+ File.open(pub_key, 'w') {|f| f.write(key.ssh_public_key)}
282
+
283
+ ssh_add
284
+ end
285
+ pub_key
286
+ end
287
+
288
+ def exe?(executable)
289
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? do |directory|
290
+ File.executable?(File.join(directory, executable.to_s))
291
+ end
292
+ end
293
+
294
+ # For Net::SSH versions (< 2.0.11) that does not have
295
+ # Net::SSH::KeyFactory.load_public_key, we drop to shell to get
296
+ # the key's fingerprint
297
+ def ssh_keygen_fallback(path)
298
+ fingerprint = `ssh-keygen -lf #{path} 2>&1`.split(' ')[1]
299
+
300
+ if $?.exitstatus != 0
301
+ error "Unable to compute SSH public key finger print for #{path}"
302
+ end
303
+ fingerprint
304
+ end
305
+
306
+ def fingerprint_for_local_key(key)
307
+ Net::SSH::KeyFactory.load_public_key(key).fingerprint
308
+ rescue NoMethodError, NotImplementedError => e
309
+ ssh_keygen_fallback key
310
+ nil
311
+ rescue OpenSSL::PKey::PKeyError, Net::SSH::Exception => e
312
+ error e.message
313
+ nil
314
+ rescue => e
315
+ debug e.message
316
+ nil
317
+ end
318
+
319
+ def fingerprint_for_default_key
320
+ fingerprint_for_local_key(RHC::Config.ssh_pub_key_file_path)
321
+ end
322
+
323
+ # for an SSH public key specified by 'key', return a triple
324
+ # [type, content, comment]
325
+ # which is basically the space-separated list of the SSH public key content
326
+ def ssh_key_triple_for(key)
327
+ begin
328
+ IO.read(key).chomp.split
329
+ rescue Errno::ENOENT => e
330
+ raise ::RHC::KeyFileNotExistentException.new("File '#{key}' does not exist.")
331
+ rescue Errno::EACCES => e
332
+ raise ::RHC::KeyFileAccessDeniedException.new("Access denied to '#{key}'.")
333
+ end
334
+ end
335
+
336
+ def ssh_key_triple_for_default_key
337
+ ssh_key_triple_for(RHC::Config.ssh_pub_key_file_path)
338
+ end
339
+
340
+ # check the version of SSH that is installed
341
+ def ssh_version
342
+ @ssh_version ||= `ssh -V 2>&1`.strip
343
+ end
344
+
345
+ # return whether or not SSH is installed
346
+ def has_ssh?
347
+ @has_ssh ||= begin
348
+ @ssh_version = nil
349
+ ssh_version
350
+ $?.success?
351
+ rescue
352
+ false
353
+ end
354
+ end
355
+
356
+ # return supplied ssh executable, if valid (executable, searches $PATH).
357
+ # if none was supplied, return installed ssh, if any.
358
+ def check_ssh_executable!(path)
359
+ if not path
360
+ raise RHC::InvalidSSHExecutableException.new("No system SSH available. Please use the --ssh option to specify the path to your SSH executable, or install SSH.") unless has_ssh?
361
+ 'ssh'
362
+ else
363
+ bin_path = path.split(' ').first
364
+ raise RHC::InvalidSSHExecutableException.new("SSH executable '#{bin_path}' does not exist.") unless File.exist?(bin_path) or exe?(bin_path)
365
+ raise RHC::InvalidSSHExecutableException.new("SSH executable '#{bin_path}' is not executable.") unless File.executable?(bin_path) or exe?(bin_path)
366
+ path
367
+ end
368
+ end
369
+
370
+ private
371
+
372
+ def ssh_add
373
+ if exe?('ssh-add')
374
+ #:nocov:
375
+ `ssh-add 2>&1`
376
+ #:nocov:
377
+ end
378
+ end
379
+ end
380
+ end
data/lib/rhc/tar_gz.rb ADDED
@@ -0,0 +1,51 @@
1
+ require 'stringio'
2
+ require 'archive/tar/minitar'
3
+ include Archive::Tar
4
+
5
+ TAR_BIN = File.executable?('/usr/bin/gnutar') ? '/usr/bin/gnutar' : 'tar'
6
+
7
+ module RHC
8
+
9
+ module TarGz
10
+
11
+ def self.contains(filename, search, force_ruby=false)
12
+
13
+ return false if ! (File.file? filename and File.basename(filename).downcase =~ /.\.t(ar\.)?gz$/i)
14
+
15
+ regex = Regexp.new search
16
+ if RHC::Helpers.windows? or RHC::Helpers.mac? or force_ruby
17
+ begin
18
+ zlib::GzipReader.open(filename) do |gz|
19
+ Minitar::Reader.open gz do |tar|
20
+ tar.each_entry do |entry|
21
+ if entry.full_name =~ regex
22
+ return true
23
+ end
24
+ end
25
+ end
26
+ end
27
+ rescue zlib::GzipFile::Error, zlib::GzipFile::Error
28
+ false
29
+ end
30
+ else
31
+ # combining STDOUT and STDERR (i.e., 2>&1) does not suppress output
32
+ # when the specs run via 'bundle exec rake spec'
33
+ system "#{TAR_BIN} --wildcards -tf '#{filename}' '#{regex.source}' 2>/dev/null >/dev/null"
34
+ end
35
+ end
36
+
37
+ private
38
+ def self.zlib
39
+ #:nocov:
40
+ require 'zlib' rescue nil
41
+ if defined? Zlib::GzipReader
42
+ Zlib
43
+ else
44
+ require 'rhc/vendor/zliby'
45
+ RHC::Vendor::Zlib
46
+ end
47
+ #:nocov:
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,51 @@
1
+ Usage: <%= Array(program :name).first %> <%= @command.name %> <%= @command.syntax %>
2
+
3
+ <%= @command.description || @command.summary %>
4
+ <% if @actions.blank? or @command.root? and @command.info[:method].present? -%>
5
+
6
+ <% unless @command.info[:args].blank? or @command.options.all?{ |o| o[:hide] or o[:switches].present? } -%>
7
+
8
+ Arguments
9
+ <%= table(
10
+ @command.info[:args].select do |opt|
11
+ not opt[:hide] and not opt[:switches].present?
12
+ end.map do |opt|
13
+ [opt[:name], opt[:description]]
14
+ end,
15
+ table_args(' ', 25)
16
+ ).join("\n") %>
17
+ <% end -%>
18
+ <% unless @command.options.blank? or @command.options.all?{ |o| o[:hide] } -%>
19
+
20
+ Options
21
+ <%= table(
22
+ @command.options.select do |opt|
23
+ not opt[:hide]
24
+ end.map do |opt|
25
+ [opt[:switches].join(', '), opt[:description]]
26
+ end,
27
+ table_args(' ', 25)
28
+ ).join("\n") %>
29
+ <% end -%>
30
+
31
+ Global Options
32
+ <%= table(
33
+ @global_options.select do |opt|
34
+ not (opt[:hide] || @command.options.any?{ |o| (o[:switches] & opt[:switches]).present? })
35
+ end.map do |opt|
36
+ [opt[:switches].join(', '), opt[:description]]
37
+ end,
38
+ table_args(' ', 25)
39
+ ).join("\n") %>
40
+
41
+ See '<%= Array(program :name).first %> help options' for a full list of global options.
42
+ <% end -%>
43
+ <% if @actions.present? -%>
44
+
45
+ List of Actions
46
+ <%= table(@actions.map{ |a| [a[:name], a[:summary]] }, table_args(' ', 13)).join("\n") %>
47
+ <% if @command.default_action? -%>
48
+
49
+ The default action for this resource is '<%= @command.default_action %>'
50
+ <% end -%>
51
+ <% end -%>
@@ -0,0 +1,11 @@
1
+ Usage: <%= Array(program :name).first %> <%= @command.name %><%= " #{@command.syntax}" if @command.syntax %>
2
+ <% unless @command.options.blank? or @command.options.all?{ |o| o[:hide] } -%>
3
+ Pass '--help' to see the full list of options
4
+ <% end -%>
5
+ <% unless @actions.nil? or @actions.empty? -%>
6
+
7
+ <%= @command.description || @command.summary %>
8
+
9
+ List of Actions
10
+ <%= table(@actions.map{ |a| [a[:name], a[:summary]] }, table_args(' ', 18)).join("\n") %>
11
+ <% end -%>