startapp 0.1.6

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