pbox 1.17.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +40 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/pbox_bash +1639 -0
  7. data/bin/pbox +37 -0
  8. data/conf/protonbox.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +178 -0
  11. data/features/deployments_feature.rb +127 -0
  12. data/features/domains_feature.rb +49 -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 +186 -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 +701 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +96 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +326 -0
  31. data/lib/rhc/commands/deployment.rb +82 -0
  32. data/lib/rhc/commands/domain.rb +167 -0
  33. data/lib/rhc/commands/env.rb +142 -0
  34. data/lib/rhc/commands/git_clone.rb +29 -0
  35. data/lib/rhc/commands/logout.rb +51 -0
  36. data/lib/rhc/commands/member.rb +148 -0
  37. data/lib/rhc/commands/port_forward.rb +197 -0
  38. data/lib/rhc/commands/server.rb +40 -0
  39. data/lib/rhc/commands/setup.rb +60 -0
  40. data/lib/rhc/commands/snapshot.rb +137 -0
  41. data/lib/rhc/commands/ssh.rb +51 -0
  42. data/lib/rhc/commands/sshkey.rb +97 -0
  43. data/lib/rhc/commands/tail.rb +47 -0
  44. data/lib/rhc/commands/threaddump.rb +14 -0
  45. data/lib/rhc/commands.rb +396 -0
  46. data/lib/rhc/config.rb +320 -0
  47. data/lib/rhc/context_helper.rb +121 -0
  48. data/lib/rhc/core_ext.rb +202 -0
  49. data/lib/rhc/coverage_helper.rb +33 -0
  50. data/lib/rhc/deployment_helpers.rb +88 -0
  51. data/lib/rhc/exceptions.rb +232 -0
  52. data/lib/rhc/git_helpers.rb +91 -0
  53. data/lib/rhc/help_formatter.rb +55 -0
  54. data/lib/rhc/helpers.rb +477 -0
  55. data/lib/rhc/highline_extensions.rb +479 -0
  56. data/lib/rhc/json.rb +51 -0
  57. data/lib/rhc/output_helpers.rb +260 -0
  58. data/lib/rhc/rest/activation.rb +11 -0
  59. data/lib/rhc/rest/alias.rb +42 -0
  60. data/lib/rhc/rest/api.rb +87 -0
  61. data/lib/rhc/rest/application.rb +332 -0
  62. data/lib/rhc/rest/attributes.rb +36 -0
  63. data/lib/rhc/rest/authorization.rb +8 -0
  64. data/lib/rhc/rest/base.rb +79 -0
  65. data/lib/rhc/rest/cartridge.rb +154 -0
  66. data/lib/rhc/rest/client.rb +650 -0
  67. data/lib/rhc/rest/deployment.rb +18 -0
  68. data/lib/rhc/rest/domain.rb +98 -0
  69. data/lib/rhc/rest/environment_variable.rb +15 -0
  70. data/lib/rhc/rest/gear_group.rb +16 -0
  71. data/lib/rhc/rest/httpclient.rb +145 -0
  72. data/lib/rhc/rest/key.rb +44 -0
  73. data/lib/rhc/rest/membership.rb +105 -0
  74. data/lib/rhc/rest/mock.rb +1024 -0
  75. data/lib/rhc/rest/user.rb +32 -0
  76. data/lib/rhc/rest.rb +148 -0
  77. data/lib/rhc/ssh_helpers.rb +378 -0
  78. data/lib/rhc/tar_gz.rb +51 -0
  79. data/lib/rhc/usage_templates/command_help.erb +51 -0
  80. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  81. data/lib/rhc/usage_templates/help.erb +35 -0
  82. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  83. data/lib/rhc/usage_templates/options_help.erb +12 -0
  84. data/lib/rhc/vendor/okjson.rb +600 -0
  85. data/lib/rhc/vendor/parseconfig.rb +178 -0
  86. data/lib/rhc/vendor/sshkey.rb +253 -0
  87. data/lib/rhc/vendor/zliby.rb +628 -0
  88. data/lib/rhc/version.rb +5 -0
  89. data/lib/rhc/wizard.rb +633 -0
  90. data/lib/rhc.rb +34 -0
  91. data/spec/coverage_helper.rb +89 -0
  92. data/spec/direct_execution_helper.rb +338 -0
  93. data/spec/keys/example.pem +23 -0
  94. data/spec/keys/example_private.pem +27 -0
  95. data/spec/keys/server.pem +19 -0
  96. data/spec/rest_spec_helper.rb +31 -0
  97. data/spec/rhc/assets/cert.crt +22 -0
  98. data/spec/rhc/assets/cert_key_rsa +27 -0
  99. data/spec/rhc/assets/empty.txt +0 -0
  100. data/spec/rhc/assets/env_vars.txt +7 -0
  101. data/spec/rhc/assets/env_vars_2.txt +1 -0
  102. data/spec/rhc/assets/foo.txt +1 -0
  103. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  104. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  105. data/spec/rhc/auth_spec.rb +442 -0
  106. data/spec/rhc/cli_spec.rb +188 -0
  107. data/spec/rhc/command_spec.rb +435 -0
  108. data/spec/rhc/commands/account_spec.rb +42 -0
  109. data/spec/rhc/commands/alias_spec.rb +333 -0
  110. data/spec/rhc/commands/app_spec.rb +754 -0
  111. data/spec/rhc/commands/apps_spec.rb +39 -0
  112. data/spec/rhc/commands/authorization_spec.rb +145 -0
  113. data/spec/rhc/commands/cartridge_spec.rb +641 -0
  114. data/spec/rhc/commands/deployment_spec.rb +286 -0
  115. data/spec/rhc/commands/domain_spec.rb +383 -0
  116. data/spec/rhc/commands/env_spec.rb +493 -0
  117. data/spec/rhc/commands/git_clone_spec.rb +80 -0
  118. data/spec/rhc/commands/logout_spec.rb +86 -0
  119. data/spec/rhc/commands/member_spec.rb +228 -0
  120. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  121. data/spec/rhc/commands/server_spec.rb +69 -0
  122. data/spec/rhc/commands/setup_spec.rb +118 -0
  123. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  124. data/spec/rhc/commands/ssh_spec.rb +163 -0
  125. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  126. data/spec/rhc/commands/tail_spec.rb +81 -0
  127. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  128. data/spec/rhc/config_spec.rb +407 -0
  129. data/spec/rhc/helpers_spec.rb +524 -0
  130. data/spec/rhc/highline_extensions_spec.rb +314 -0
  131. data/spec/rhc/json_spec.rb +30 -0
  132. data/spec/rhc/rest_application_spec.rb +248 -0
  133. data/spec/rhc/rest_client_spec.rb +752 -0
  134. data/spec/rhc/rest_spec.rb +740 -0
  135. data/spec/rhc/targz_spec.rb +55 -0
  136. data/spec/rhc/wizard_spec.rb +756 -0
  137. data/spec/spec_helper.rb +575 -0
  138. data/spec/wizard_spec_helper.rb +330 -0
  139. metadata +435 -0
data/lib/rhc/wizard.rb ADDED
@@ -0,0 +1,633 @@
1
+ require 'rhc'
2
+ require 'fileutils'
3
+ require 'socket'
4
+
5
+ module RHC
6
+ class Wizard
7
+ include HighLine::SystemExtensions
8
+
9
+ def self.has_configuration?
10
+ File.exists? RHC::Config.local_config_path
11
+ end
12
+
13
+ DEFAULT_MAX_LENGTH = 16
14
+
15
+ CONFIG_STAGES = [
16
+ :login_stage,
17
+ :create_config_stage,
18
+ ]
19
+ KEY_STAGES = [
20
+ :config_ssh_key_stage,
21
+ :upload_ssh_key_stage,
22
+ ]
23
+ TEST_STAGES = [
24
+ :install_client_tools_stage,
25
+ :setup_test_stage,
26
+ ]
27
+ NAMESPACE_STAGES = [
28
+ :config_namespace_stage,
29
+ ]
30
+ APP_STAGES = [
31
+ :show_app_info_stage,
32
+ ]
33
+ STAGES = [:greeting_stage] + CONFIG_STAGES + KEY_STAGES + TEST_STAGES + NAMESPACE_STAGES + APP_STAGES + [:finalize_stage]
34
+
35
+ def stages
36
+ STAGES
37
+ end
38
+
39
+ attr_reader :rest_client
40
+
41
+ #
42
+ # Running the setup wizard may change the contents of opts and config if
43
+ # the create_config_stage completes successfully.
44
+ #
45
+ def initialize(config=RHC::Config.new, opts=Commander::Command::Options.new)
46
+ @config = config
47
+ @options = opts
48
+ end
49
+
50
+ # Public: Runs the setup wizard to make sure ~/.protonbox and ~/.ssh are correct
51
+ #
52
+ # Examples
53
+ #
54
+ # wizard.run()
55
+ # # => true
56
+ #
57
+ # Returns nil on failure or true on success
58
+ def run
59
+ stages.each do |stage|
60
+ debug "Running #{stage}"
61
+ if self.send(stage).nil?
62
+ return nil
63
+ end
64
+ end
65
+ true
66
+ end
67
+
68
+ protected
69
+
70
+ include RHC::Helpers
71
+ include RHC::SSHHelpers
72
+ include RHC::GitHelpers
73
+ include RHC::CartridgeHelpers
74
+ attr_reader :config, :options
75
+ attr_accessor :auth, :user
76
+ attr_writer :rest_client
77
+
78
+ def hostname
79
+ Socket.gethostname
80
+ end
81
+
82
+ def protonbox_server
83
+ options.server || config['protonbox_server'] || "api.protonbox.com"
84
+ end
85
+
86
+ def new_client_for_options
87
+ client_from_options({
88
+ :auth => auth,
89
+ })
90
+ end
91
+
92
+ def core_auth
93
+ @core_auth ||= RHC::Auth::Basic.new(options)
94
+ end
95
+
96
+ def token_auth
97
+ RHC::Auth::Token.new(options, core_auth, token_store)
98
+ end
99
+
100
+ def auth(reset=false)
101
+ @auth = nil if reset
102
+ @auth ||= begin
103
+ if options.token
104
+ token_auth
105
+ else
106
+ core_auth
107
+ end
108
+ end
109
+ end
110
+
111
+ def token_store
112
+ @token_store ||= RHC::Auth::TokenStore.new(config.home_conf_path)
113
+ end
114
+
115
+ def username
116
+ options.pblogin || (auth.username if auth.respond_to?(:username))
117
+ end
118
+
119
+ def print_dot
120
+ $terminal.instance_variable_get(:@output).print('.')
121
+ end
122
+
123
+
124
+ # cache SSH keys from the REST client
125
+ def ssh_keys
126
+ @ssh_keys ||= rest_client.sshkeys
127
+ end
128
+
129
+ # clear SSH key cache
130
+ def clear_ssh_keys_cache
131
+ @ssh_keys = nil
132
+ end
133
+
134
+ # return true if the account has the public key defined by
135
+ # RHC::Config::ssh_pub_key_file_path
136
+ def ssh_key_uploaded?
137
+ ssh_keys.present? && ssh_keys.any? { |k| k.fingerprint.present? && k.fingerprint == fingerprint_for_default_key }
138
+ end
139
+
140
+ def existing_keys_info
141
+ return unless ssh_keys
142
+ indent{ ssh_keys.each{ |key| paragraph{ display_key(key) } } }
143
+ end
144
+
145
+ def applications
146
+ @applications ||= rest_client.domains.map(&:applications).flatten
147
+ end
148
+
149
+ def namespace_optional?
150
+ true
151
+ end
152
+
153
+ #
154
+ # Stages
155
+ #
156
+
157
+ def greeting_stage
158
+ info "ProtonBox Client Tools (PBOX) Setup Wizard"
159
+
160
+ paragraph do
161
+ say "This wizard will help you upload your SSH keys, set your application namespace, and check that other programs like Git are properly installed."
162
+ end
163
+
164
+ true
165
+ end
166
+
167
+ def login_stage
168
+ if token_for_user
169
+ options.token = token_for_user
170
+ say "Using an existing token for #{options.pblogin} to login to #{protonbox_server}"
171
+ elsif options.pblogin
172
+ say "Using #{options.pblogin} to login to #{protonbox_server}"
173
+ end
174
+
175
+ self.rest_client = new_client_for_options
176
+
177
+ begin
178
+ rest_client.api
179
+ rescue RHC::Rest::CertificateVerificationFailed => e
180
+ debug "Certificate validation failed: #{e.reason}"
181
+ unless options.insecure
182
+ if RHC::Rest::SelfSignedCertificate === e
183
+ warn "The server's certificate is self-signed, which means that a secure connection can't be established to '#{protonbox_server}'."
184
+ else
185
+ warn "The server's certificate could not be verified, which means that a secure connection can't be established to '#{protonbox_server}'."
186
+ end
187
+ if protonbox_online_server?
188
+ paragraph{ warn "This may mean that a server between you and ProtonBox is capable of accessing information sent from this client. If you wish to continue without checking the certificate, please pass the -k (or --insecure) option to this command." }
189
+ return
190
+ else
191
+ paragraph{ warn "You may bypass this check, but any data you send to the server could be intercepted by others." }
192
+ return unless agree "Connect without checking the certificate? (yes|no): "
193
+ options.insecure = true
194
+ self.rest_client = new_client_for_options
195
+ retry
196
+ end
197
+ end
198
+ end
199
+
200
+ self.user = rest_client.user
201
+ options.pblogin = self.user.login unless username
202
+
203
+ if rest_client.supports_sessions? && !options.token && options.create_token != false
204
+ paragraph do
205
+ info "ProtonBox can create and store a token on disk which allows to you to access the server without using your password. The key is stored in your home directory and should be kept secret. You can delete the key at any time by running 'pbox logout'."
206
+ if options.create_token or agree "Generate a token now? (yes|no) "
207
+ say "Generating an authorization token for this client ... "
208
+ token = rest_client.new_session
209
+ options.token = token.token
210
+ self.auth(true).save(token.token)
211
+ self.rest_client = new_client_for_options
212
+ self.user = rest_client.user
213
+
214
+ success "lasts #{distance_of_time_in_words(token.expires_in_seconds)}"
215
+ end
216
+ end
217
+ end
218
+ true
219
+ end
220
+
221
+ def create_config_stage
222
+ paragraph do
223
+ if File.exists? config.path
224
+ backup = "#{@config.path}.bak"
225
+ FileUtils.cp(config.path, backup)
226
+ FileUtils.rm(config.path)
227
+ end
228
+
229
+ say "Saving configuration to #{system_path(config.path)} ... "
230
+
231
+ changed = Commander::Command::Options.new(options)
232
+ changed.pblogin = username
233
+ changed.password = nil
234
+ changed.use_authorization_tokens = options.create_token != false && !changed.token.nil?
235
+
236
+ FileUtils.mkdir_p File.dirname(config.path)
237
+ config.save!(changed)
238
+ options.__replace__(changed)
239
+
240
+ success "done"
241
+ end
242
+
243
+ true
244
+ end
245
+
246
+ def config_ssh_key_stage
247
+ if config.should_run_ssh_wizard?
248
+ paragraph{ say "No SSH keys were found. We will generate a pair of keys for you." }
249
+
250
+ ssh_pub_key_file_path = generate_ssh_key_ruby
251
+ paragraph{ say " Created: #{ssh_pub_key_file_path}" }
252
+ end
253
+ true
254
+ end
255
+
256
+ def upload_ssh_key_stage
257
+ return true if ssh_key_uploaded?
258
+
259
+ upload = paragraph do
260
+ agree "Your public SSH key must be uploaded to the ProtonBox server to access code. Upload now? (yes|no) "
261
+ end
262
+
263
+ if upload
264
+ if ssh_keys.empty?
265
+ paragraph do
266
+ info "Since you do not have any keys associated with your ProtonBox account, "\
267
+ "your new key will be uploaded as the 'default' key."
268
+ upload_ssh_key('default')
269
+ end
270
+ else
271
+ paragraph { existing_keys_info }
272
+
273
+ key_fingerprint = fingerprint_for_default_key
274
+ unless key_fingerprint
275
+ paragraph do
276
+ warn "Your public SSH key at #{system_path(RHC::Config.ssh_pub_key_file_path)} is invalid or unreadable. "\
277
+ "Setup can not continue until you manually remove or fix your "\
278
+ "public and private keys id_rsa keys."
279
+ end
280
+ return false
281
+ end
282
+
283
+ paragraph do
284
+ say "You can enter a name for your key, or leave it blank to use the default name. " \
285
+ "Using the same name as an existing key will overwrite the old key."
286
+ end
287
+ ask_for_key_name
288
+ end
289
+ else
290
+ paragraph do
291
+ info "You can upload your public SSH key at a later time using the 'pbox sshkey' command"
292
+ end
293
+ end
294
+
295
+ true
296
+ end
297
+
298
+ def ask_for_key_name(default_name=get_preferred_key_name)
299
+ key_name = nil
300
+ paragraph do
301
+ begin
302
+ key_name = ask "Provide a name for this key: " do |q|
303
+ q.default = default_name
304
+ q.responses[:ask_on_error] = ''
305
+ end
306
+ end while !upload_ssh_key(key_name)
307
+ end
308
+ end
309
+
310
+ def get_preferred_key_name
311
+ userkey = username ? username.gsub(/@.*/, '') : ''
312
+ pubkey_base_name = "#{userkey}#{hostname.gsub(/\..*\z/,'')}".gsub(/[^A-Za-z0-9]/,'').slice(0,16)
313
+ find_unique_key_name(pubkey_base_name)
314
+ end
315
+
316
+ # given the base name and the maximum length,
317
+ # find a name that does not clash with what is in opts[:keys]
318
+ def find_unique_key_name(base='default')
319
+ max = DEFAULT_MAX_LENGTH
320
+ key_name_suffix = 1
321
+ candidate = base
322
+ while ssh_keys.detect { |k| k.name == candidate }
323
+ candidate = base.slice(0, max - key_name_suffix.to_s.length) + key_name_suffix.to_s
324
+ key_name_suffix += 1
325
+ end
326
+ candidate
327
+ end
328
+
329
+ def upload_ssh_key(key_name)
330
+ return false unless key_name.present?
331
+
332
+ type, content, comment = ssh_key_triple_for_default_key
333
+
334
+ if ssh_keys.present? && ssh_keys.any? { |k| k.name == key_name }
335
+ clear_ssh_keys_cache
336
+ paragraph do
337
+ say "Key with the name '#{key_name}' already exists. Updating ... "
338
+ key = rest_client.find_key(key_name)
339
+ key.update(type, content)
340
+ success "done"
341
+ end
342
+ else
343
+ clear_ssh_keys_cache
344
+ begin
345
+ rest_client.add_key(key_name, content, type)
346
+ paragraph{ say "Uploading key '#{key_name}' ... #{color('done', :green)}" }
347
+ rescue RHC::Rest::ValidationException => e
348
+ error e.message || "Unknown error during key upload."
349
+ return false
350
+ end
351
+ end
352
+
353
+ true
354
+ end
355
+
356
+
357
+ ##
358
+ # Alert the user that they should manually install tools if they are not
359
+ # currently available
360
+ #
361
+ # Unix Tools:
362
+ # git
363
+ #
364
+ # Windows Tools:
365
+ # msysgit (Git for Windows)
366
+ # TortoiseGIT (Windows Explorer integration)
367
+ #
368
+ def install_client_tools_stage
369
+ if windows?
370
+ windows_install
371
+ else
372
+ generic_unix_install_check
373
+ end
374
+ true
375
+ end
376
+
377
+ def config_namespace_stage
378
+ paragraph do
379
+ say "Checking for a domain ... "
380
+ domains = rest_client.domains
381
+ if domains.length == 0
382
+ warn "none"
383
+
384
+ paragraph do
385
+ say [
386
+ "Applications are grouped into domains - each domain has a unique name (called a namespace) that becomes part of your public application URL.",
387
+ ("You may create your first domain here or leave it blank and use 'pbox create-domain' later." if namespace_optional?),
388
+ "You will not be able to create an application without completing this step.",
389
+ ].compact.join(' ')
390
+ end
391
+
392
+ ask_for_namespace
393
+ else
394
+ success domains.map(&:name).join(', ')
395
+ end
396
+ end
397
+
398
+ true
399
+ end
400
+
401
+ def show_app_info_stage
402
+ section do
403
+ say "Checking for applications ... "
404
+
405
+ if !applications.nil? and !applications.empty?
406
+ success "found #{applications.length}"
407
+
408
+ paragraph do
409
+ indent do
410
+ say table(applications.map do |app|
411
+ [app.name, app.app_url]
412
+ end)
413
+ end
414
+ end
415
+ else
416
+ info "none"
417
+
418
+ paragraph{ say "Run 'pbox create-app' to create your first application." }
419
+ paragraph do
420
+ say table(standalone_cartridges.sort {|a,b| a.display_name <=> b.display_name }.map do |cart|
421
+ [' ', cart.display_name, "pbox create-app <app name> #{cart.name}"]
422
+ end)
423
+ end
424
+ end
425
+ paragraph do
426
+ indent do
427
+ say "You are using #{color(self.user.consumed_gears.to_s, :green)} of #{color(self.user.max_gears.to_s, :green)} total gears" if user.max_gears.is_a? Fixnum
428
+ say "The following gear sizes are available to you: #{self.user.capabilities.gear_sizes.join(', ')}" if user.capabilities.gear_sizes.present?
429
+ end
430
+ end
431
+ end
432
+ true
433
+ end
434
+
435
+ # Perform basic tests to ensure that setup is sane
436
+ # search for private methods starting with "test_" and execute them
437
+ # in alphabetical order
438
+ # NOTE: The order itself is not important--the tests should be independent.
439
+ # However, the hash order is unpredictable in Ruby 1.8, and is preserved in
440
+ # 1.9. There are two similar tests that can fail under the same conditions,
441
+ # and this makes the spec results inconsistent between 1.8 and 1.9.
442
+ # Thus, we force an order with #sort to ensure spec passage on both.
443
+ def setup_test_stage
444
+ say "Checking common problems "
445
+ failed = false
446
+ all_test_methods.sort.each do |test|
447
+ begin
448
+ send(test)
449
+ print_dot unless failed
450
+ true
451
+ rescue => e
452
+ say "\n" unless failed
453
+ failed = true
454
+ paragraph{ error e.message }
455
+ false
456
+ end
457
+ end.tap do |pass|
458
+ success(' done') if !failed
459
+ end
460
+
461
+ true
462
+ end
463
+
464
+ def all_test_methods
465
+ (protected_methods + private_methods).select {|m| m.to_s.start_with? 'test_'}
466
+ end
467
+
468
+ ###
469
+ # tests for specific user errors
470
+
471
+ def test_private_key_mode
472
+ pub_key_file = RHC::Config.ssh_pub_key_file_path
473
+ private_key_file = RHC::Config.ssh_priv_key_file_path
474
+ if File.exist?(private_key_file)
475
+ unless File.stat(private_key_file).mode.to_s(8) =~ /[4-7]00$/
476
+ raise "Your private SSH key file should be set as readable only to yourself. Please run 'chmod 600 #{system_path(private_key_file)}'"
477
+ end
478
+ end
479
+ true
480
+ end
481
+
482
+ # test connectivity an app
483
+ def test_ssh_connectivity
484
+ return true unless ssh_key_uploaded?
485
+
486
+ applications.take(1).each do |app|
487
+ begin
488
+ host, user = RHC::Helpers.ssh_string_parts(app.ssh_url)
489
+ ssh = Net::SSH.start(host, user, :timeout => 60)
490
+ rescue Interrupt => e
491
+ debug_error(e)
492
+ raise "Connection attempt to #{app.host} was interrupted"
493
+ rescue ::Exception => e
494
+ debug_error(e)
495
+ raise "An SSH connection could not be established to #{app.host}. Your SSH configuration may not be correct, or the application may not be responding. #{e.message} (#{e.class})"
496
+ ensure
497
+ ssh.close if ssh
498
+ end
499
+ end
500
+ true
501
+ end
502
+
503
+ ###
504
+ def finalize_stage
505
+ paragraph do
506
+ say "The ProtonBox client tools have been configured on your computer. " \
507
+ "You can run this setup wizard at any time by using the command 'pbox setup' " \
508
+ "We will now execute your original " \
509
+ "command (pbox #{ARGV.join(" ")})"
510
+ end
511
+ true
512
+ end
513
+
514
+ def config_namespace(namespace)
515
+ # skip if string is empty
516
+ if namespace_optional? and (namespace.nil? or namespace.chomp.blank?)
517
+ paragraph{ info "You may create a domain later through 'pbox create-domain'" }
518
+ return true
519
+ end
520
+
521
+ begin
522
+ domain = rest_client.add_domain(namespace)
523
+ options.namespace = namespace
524
+
525
+ success "Your domain '#{domain.name}' has been successfully created"
526
+ rescue RHC::Rest::ValidationException => e
527
+ error e.message || "Unknown error during domain creation."
528
+ return false
529
+ end
530
+ true
531
+ end
532
+
533
+ def ask_for_namespace
534
+ # Ask for a namespace at least once, configure the namespace if a valid,
535
+ # non-blank string is provided.
536
+ namespace = nil
537
+ paragraph do
538
+ begin
539
+ namespace = ask "Please enter a namespace (letters and numbers only)#{namespace_optional? ? " |<none>|" : ""}: " do |q|
540
+ q.responses[:ask_on_error] = ''
541
+ end
542
+ end while !config_namespace(namespace)
543
+ end
544
+ end
545
+
546
+ def generic_unix_install_check
547
+ paragraph do
548
+ say "Checking for git ... "
549
+
550
+ if has_git?
551
+ success("found #{git_version}") rescue success('found')
552
+ else
553
+ warn "needs to be installed"
554
+
555
+ paragraph do
556
+ say "Automated installation of client tools is not supported for " \
557
+ "your platform. You will need to manually install git for full " \
558
+ "ProtonBox functionality."
559
+ end
560
+ end
561
+ end
562
+ end
563
+
564
+ def windows_install
565
+ # Finding windows executables is hard since they can get installed
566
+ # in non standard directories. Punt on this for now and simply
567
+ # print out urls and some instructions
568
+ warn <<EOF
569
+
570
+ In order to fully interact with ProtonBox you will need to install and configure a git client if you have not already done so.
571
+
572
+ Documentation for installing other tools you will need for ProtonBox can be found at http://devcenter.protonbox.com/getting-started
573
+
574
+ We recommend these free applications:
575
+
576
+ * Git for Windows - a basic git command line and GUI client http://git-scm.com/download/win
577
+
578
+ EOF
579
+ end
580
+ end
581
+
582
+ class RerunWizard < Wizard
583
+ def finalize_stage
584
+ section :top => 1 do
585
+ success "Your client tools are now configured."
586
+ end
587
+ true
588
+ end
589
+ end
590
+
591
+ class EmbeddedWizard < Wizard
592
+ def stages
593
+ super - APP_STAGES - KEY_STAGES - [:setup_test_stage]
594
+ end
595
+
596
+ def finalize_stage
597
+ true
598
+ end
599
+
600
+ protected
601
+ def namespace_optional?
602
+ false
603
+ end
604
+ end
605
+
606
+ class DomainWizard < Wizard
607
+ def initialize(*args)
608
+ client = args.length == 3 ? args.pop : nil
609
+ super *args
610
+ self.rest_client = client || new_client_for_options
611
+ end
612
+
613
+ def stages
614
+ [:config_namespace_stage]
615
+ end
616
+
617
+ protected
618
+ def namespace_optional?
619
+ false
620
+ end
621
+ end
622
+
623
+ class SSHWizard < Wizard
624
+ def stages
625
+ KEY_STAGES
626
+ end
627
+
628
+ def initialize(rest_client, config, options)
629
+ self.rest_client = rest_client
630
+ super config, options
631
+ end
632
+ end
633
+ end
data/lib/rhc.rb ADDED
@@ -0,0 +1,34 @@
1
+ # require 'rhc/version' #FIXME gem should know version
2
+
3
+ # Only require external gem dependencies here
4
+ require 'logger'
5
+ require 'pp'
6
+
7
+ require 'pry' if ENV['PRY']
8
+
9
+ # Extend core methods
10
+ require 'rhc/core_ext'
11
+
12
+ module RHC
13
+ autoload :AutoComplete, 'rhc/autocomplete'
14
+ autoload :Auth, 'rhc/auth'
15
+ autoload :CartridgeHelpers, 'rhc/cartridge_helpers'
16
+ autoload :CommandRunner, 'rhc/command_runner'
17
+ autoload :Commands, 'rhc/commands'
18
+ autoload :Config, 'rhc/config'
19
+ autoload :GitHelpers, 'rhc/git_helpers'
20
+ autoload :Helpers, 'rhc/helpers'
21
+ autoload :HelpFormatter, 'rhc/help_formatter'
22
+ autoload :Rest, 'rhc/rest'
23
+ autoload :SSHHelpers, 'rhc/ssh_helpers'
24
+ autoload :TarGz, 'rhc/tar_gz'
25
+ autoload :VERSION, 'rhc/version'
26
+ end
27
+
28
+ require 'rhc/exceptions'
29
+
30
+ require 'commander'
31
+ require 'commander/delegates'
32
+ require 'highline/system_extensions'
33
+
34
+ require 'rhc/highline_extensions'