rhc 1.15.6 → 1.16.9

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.
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'direct_execution_helper'
3
+
4
+ describe "rhc sshkey scenarios" do
5
+ context "with an existing domain" do
6
+ before(:all) do
7
+ standard_config
8
+ @domain = has_a_domain
9
+ end
10
+
11
+ let(:domain){ @domain }
12
+
13
+ context "with an application" do
14
+ before{ has_an_application }
15
+
16
+ it "should add and remove kerberos keys on gear" do
17
+ app = @domain.applications.first
18
+ keyname = "key#{rand(1000000000000)}"
19
+ keycontent = "principal#{rand(1000000000000)}"
20
+
21
+ r = rhc 'sshkey', 'add', keyname, '--type', 'krb5-principal', '--content', keycontent
22
+ r.status.should == 0
23
+
24
+ r = rhc 'ssh', app.name, '-n', domain.name, '--ssh', ssh_exec_for_env, '--', 'if [ -f .k5login ]; then cat .k5login; fi'
25
+ r.status.should == 0
26
+ r.stdout.should match(Regexp.new("#{keyname}\n#{keycontent}"))
27
+
28
+ r = rhc 'sshkey', 'remove', keyname
29
+ r.status.should == 0
30
+
31
+ r = rhc 'ssh', app.name, '-n', domain.name, '--ssh', ssh_exec_for_env, '--', 'if [ -f .k5login ]; then cat .k5login; fi'
32
+ r.status.should == 0
33
+ r.stdout.should_not match(Regexp.new("#{keyname}\n#{keycontent}"))
34
+ end
35
+ end
36
+ end
37
+ end
@@ -113,7 +113,7 @@ describe "rhc member scenarios" do
113
113
 
114
114
  it "should reject a non-existent user" do
115
115
  r = rhc 'add-member', 'not-a-user', '-n', domain.name
116
- r.status.should_not == 1
116
+ r.status.to_i.should == 256
117
117
  r.stdout.should match "There is no account with login not-a-user."
118
118
  client.find_domain(domain.name).members.length.should == 1
119
119
  end
@@ -127,5 +127,40 @@ describe "rhc member scenarios" do
127
127
  client.find_domain(domain.name).members.any?{ |m| m.id == user.id && m.editor? }.should be_true
128
128
  end
129
129
  end
130
+
131
+ context "with an application" do
132
+ let(:other_user){ other_users.values.first }
133
+ before{ has_an_application }
134
+ before{ has_local_ssh_key(other_user) }
135
+
136
+ it "should allow SSH only for admin and edit roles" do
137
+ user = other_user.login
138
+ name = @domain.applications.first.name
139
+
140
+ r = rhc 'add-member', user, '--role', 'admin', '-n', domain.name
141
+ r.status.should == 0
142
+
143
+ with_environment(other_user) do
144
+ r = rhc 'ssh', name, '-n', domain.name, '--ssh', ssh_exec_for_env
145
+ r.status.should == 0
146
+ end
147
+
148
+ r = rhc 'add-member', user, '--role', 'view', '-n', domain.name
149
+ r.status.should == 0
150
+
151
+ with_environment(other_user) do
152
+ r = rhc 'ssh', name, '-n', domain.name, '--ssh', ssh_exec_for_env
153
+ r.status.to_i.should_not == 0
154
+ end
155
+
156
+ r = rhc 'add-member', user, '--role', 'edit', '-n', domain.name
157
+ r.status.should == 0
158
+
159
+ with_environment(other_user) do
160
+ r = rhc 'ssh', name, '-n', domain.name, '--ssh', ssh_exec_for_env
161
+ r.status.should == 0
162
+ end
163
+ end
164
+ end
130
165
  end
131
166
  end
@@ -2,6 +2,7 @@ require 'rhc/commands/base'
2
2
  require 'resolv'
3
3
  require 'rhc/git_helpers'
4
4
  require 'rhc/cartridge_helpers'
5
+ require 'rhc/deployment_helpers'
5
6
 
6
7
  module RHC::Commands
7
8
  class App < Base
@@ -105,7 +106,7 @@ module RHC::Commands
105
106
  say "Creating application '#{name}' ... "
106
107
 
107
108
  # create the main app
108
- rest_app = create_app(name, cartridges, rest_domain, options.gear_size, options.scaling, options.from_code, env)
109
+ rest_app = create_app(name, cartridges, rest_domain, options.gear_size, options.scaling, options.from_code, env, options.auto_deploy, options.keep_deployments, options.deployment_branch)
109
110
  success "done"
110
111
 
111
112
  paragraph{ indent{ success rest_app.messages.map(&:strip) } }
@@ -288,6 +289,9 @@ module RHC::Commands
288
289
  The '--state' option will retrieve information from each cartridge in
289
290
  the application, which may include cartridge specific text.
290
291
 
292
+ The '--configuration' option will display configuration values set in
293
+ the application. Use 'rhc configure-app' to configure.
294
+
291
295
  To see information about the individual gears within an application,
292
296
  use '--gears', including whether they are started or stopped and their
293
297
  SSH host strings. Passing '--gears quota' will show the free and maximum
@@ -298,10 +302,12 @@ module RHC::Commands
298
302
  rhc ssh <app> --gears '<command>'
299
303
 
300
304
  to run and display the output from each gear.
305
+
301
306
  DESC
302
307
  syntax "<app> [--namespace NAME]"
303
308
  takes_application :argument => true
304
309
  option ["--state"], "Get the current state of the cartridges in this application"
310
+ option ["--configuration"], "Get the current configuration values set in this application"
305
311
  option ["--gears [quota|ssh]"], "Show information about the cartridges on each gear in this application. Pass 'quota' to see per gear disk usage and limits. Pass 'ssh' to print only the SSH connection strings of each gear."
306
312
  def show(app_name)
307
313
 
@@ -339,6 +345,11 @@ module RHC::Commands
339
345
  end.flatten(1)
340
346
 
341
347
  say table(gear_info, :header => ['ID', 'State', 'Cartridges', 'Size', 'SSH URL'])
348
+
349
+ elsif options.configuration
350
+ display_app_configurations(find_app)
351
+ paragraph { say "Use 'rhc configure-app' to change the configuration values of this application." }
352
+
342
353
  else
343
354
  app = find_app(:include => :cartridges)
344
355
  display_app(app, app.cartridges)
@@ -347,10 +358,72 @@ module RHC::Commands
347
358
  0
348
359
  end
349
360
 
361
+ summary "Deploy a git reference or binary file of an application"
362
+ syntax "<ref> --app NAME [--namespace NAME]"
363
+ description <<-DESC
364
+ By default OpenShift applications prepare, distribute, and activate deployments
365
+ on every git push. Alternatively, a user may choose to disable automatic
366
+ deployments and use 'rhc deploy' and 'rhc deployment' commands to fully control the
367
+ deployment lifecycle.
368
+
369
+ Use this command to prepare, distribute and deploy manually from a git reference
370
+ (commit id, tag or branch) or from a binary file. Check also 'rhc configure-app'
371
+ to configure your application to deploy manually and set the number of deployments
372
+ to keep in history.
373
+
374
+ DESC
375
+ takes_application
376
+ argument :ref, "Git tag, branch or commit id or path to binary file to be deployed", ["--ref REF"], :optional => false
377
+ option "--[no-]hot-deploy", "Perform hot deployment according to the specified argument rather than checking for the presence of the hot_deploy marker in the application git repo"
378
+ option "--[no-]force-clean-build", "Perform a clean build according to the specified argument rather than checking for the presence of the force_clean_build marker in the application git repo"
379
+ alias_action :"deploy", :root_command => true
380
+ def deploy(ref)
381
+ rest_app = find_app
382
+
383
+ raise RHC::DeploymentsNotSupportedException.new if !rest_app.supports? "DEPLOY"
384
+
385
+ deploy_artifact(rest_app, ref, options.hot_deploy, options.force_clean_build)
386
+
387
+ 0
388
+ end
389
+
390
+ summary "Configure several properties that apply to an application"
391
+ syntax "<app> [--[no-]auto-deploy] [--keep-deployments INTEGER] [--deployment-branch BRANCH] [--deployment-type TYPE] [--namespace NAME]"
392
+ takes_application :argument => true
393
+ option ["--[no-]auto-deploy"], "Build and deploy automatically when pushing to the git repo. Defaults to true."
394
+ option ["--keep-deployments INTEGER", Integer], "Number of deployments to preserve. Defaults to 1."
395
+ option ["--deployment-branch BRANCH"], "Which branch should trigger an automatic deployment, if automatic deployment is enabled with --auto-deploy. Defaults to master."
396
+ option ["--deployment-type git|binary"], "Type of deployment the application accepts ('git' or 'binary'). Defaults to git."
397
+ def configure(app_name)
398
+ rest_app = find_app
399
+
400
+ app_options = {}
401
+ app_options[:auto_deploy] = options.auto_deploy if !options.auto_deploy.nil?
402
+ app_options[:keep_deployments] = options.keep_deployments if options.keep_deployments
403
+ app_options[:deployment_branch] = options.deployment_branch if options.deployment_branch
404
+ app_options[:deployment_type] = options.deployment_type if options.deployment_type
405
+
406
+ if app_options.present?
407
+ paragraph do
408
+ say "Configuring application '#{app_name}' ... "
409
+ rest_app.configure(app_options)
410
+ success "done"
411
+ end
412
+ end
413
+
414
+ paragraph { display_app(find_app, nil, [:auto_deploy, :keep_deployments, :deployment_type, :deployment_branch]) }
415
+
416
+ paragraph { say "Your application '#{rest_app.name}' is #{app_options.empty? ? '' : 'now '}configured as listed above." }
417
+ paragraph { say "Use 'rhc show-app #{rest_app.name} --configuration' to check your configuration values any time." } if app_options.present?
418
+
419
+ 0
420
+ end
421
+
350
422
  private
351
423
  include RHC::GitHelpers
352
424
  include RHC::CartridgeHelpers
353
425
  include RHC::SSHHelpers
426
+ include RHC::DeploymentHelpers
354
427
 
355
428
  MAX_RETRIES = 7
356
429
  DEFAULT_DELAY_THROTTLE = 2.0
@@ -417,13 +490,17 @@ module RHC::Commands
417
490
  result
418
491
  end
419
492
 
420
- def create_app(name, cartridges, rest_domain, gear_size=nil, scale=nil, from_code=nil, environment_variables=nil)
493
+ def create_app(name, cartridges, rest_domain, gear_size=nil, scale=nil, from_code=nil, environment_variables=nil, auto_deploy=nil, keep_deployments=nil, deployment_branch=nil)
421
494
  app_options = {:cartridges => Array(cartridges)}
422
495
  app_options[:gear_profile] = gear_size if gear_size
423
496
  app_options[:scale] = scale if scale
424
497
  app_options[:initial_git_url] = from_code if from_code
425
498
  app_options[:debug] = true if @debug
426
499
  app_options[:environment_variables] = environment_variables.map{ |item| item.to_hash } if environment_variables.present?
500
+ app_options[:auto_deploy] = auto_deploy if !auto_deploy.nil?
501
+ app_options[:keep_deployments] = keep_deployments if keep_deployments
502
+ app_options[:deployment_branch] = deployment_branch if deployment_branch
503
+ debug "Creating application '#{name}' with these options - #{app_options.inspect}"
427
504
  rest_app = rest_domain.add_application(name, app_options)
428
505
 
429
506
  rest_app
@@ -0,0 +1,82 @@
1
+ require 'rhc/commands/base'
2
+ require 'rhc/deployment_helpers'
3
+
4
+ module RHC::Commands
5
+ class Deployment < Base
6
+ include RHC::DeploymentHelpers
7
+
8
+ summary "Commands for deploying and managing deployments of an application"
9
+ description <<-DESC
10
+ By default OpenShift applications prepare, distribute, and activate deployments
11
+ on every git push. Alternatively, a user may choose to disable automatic
12
+ deployments and use this 'rhc deployment' set of commands to fully control the
13
+ deployment lifecycle. Use these commands to deploy manually from a git reference
14
+ or from a binary file, list and display deployments and also activate existing
15
+ deployments. Check also 'rhc configure-app' to configure your application to
16
+ deploy manually.
17
+
18
+ DESC
19
+ syntax "<action>"
20
+ default_action :help
21
+
22
+ summary "List the existing deployments of an application"
23
+ description <<-DESC
24
+ List all existing deployments of a given application. Check the 'rhc configure-app'
25
+ command to configure how many deployments are preserved in history.
26
+
27
+ DESC
28
+ syntax "<application>"
29
+ takes_application :argument => true
30
+ alias_action :"deployments", :root_command => true
31
+ def list(app)
32
+ rest_app = find_app
33
+ deployment_activations = rest_app.deployment_activations
34
+
35
+ raise RHC::DeploymentNotFoundException, "No deployments found for application #{app}." if !deployment_activations.present?
36
+
37
+ pager
38
+
39
+ display_deployment_list(deployment_activations)
40
+ 0
41
+ end
42
+
43
+ summary "Show details of the given deployment"
44
+ syntax "<deployment_id> --app NAME [--namespace NAME]"
45
+ description <<-DESC
46
+ Display details of the given deployment id.
47
+
48
+ DESC
49
+ takes_application
50
+ argument :id, "The deployment ID to show", ["--id ID"], :optional => false
51
+ def show(id)
52
+ rest_app = find_app
53
+ item = rest_app.deployment_activations.reverse_each.detect{|item| item[:deployment].id == id}
54
+
55
+ raise RHC::DeploymentNotFoundException, "Deployment ID '#{id}' not found for application #{rest_app.name}." if !item.present?
56
+
57
+ display_deployment(item)
58
+ paragraph { say "Use 'rhc show-app #{rest_app.name} --configuration' to check your deployment configurations." }
59
+ 0
60
+ end
61
+
62
+ summary "Activate an existing deployment"
63
+ description <<-DESC
64
+ Switch between existing deployments. This command allows you to rollback from one
65
+ deployment to a previous one or activate subsequent deployments. Check the 'rhc
66
+ configure-app' command to configure how many deployments are preserved in history.
67
+
68
+ DESC
69
+ syntax "<deployment_id> --app NAME [--namespace NAME]"
70
+ takes_application
71
+ argument :id, "The deployment ID to activate on the application", ["--id ID"], :optional => false
72
+ def activate(id)
73
+ rest_app = find_app
74
+
75
+ raise RHC::DeploymentsNotSupportedException.new if !rest_app.supports? "DEPLOY"
76
+
77
+ activate_deployment(rest_app, id)
78
+ 0
79
+ end
80
+
81
+ end
82
+ end
@@ -21,15 +21,20 @@ module RHC::Commands
21
21
  syntax "<application> [--filepath FILE] [--ssh path_to_ssh_executable]"
22
22
  takes_application :argument => true
23
23
  option ["-f", "--filepath FILE"], "Local path to save tarball (default: ./$APPNAME.tar.gz)"
24
+ option ["--deployment"], "Snapshot as a deployable file which can be deployed with 'rhc deploy'"
24
25
  option ["--ssh PATH"], "Full path to your SSH executable with additional options"
25
26
  alias_action :"app snapshot save", :root_command => true, :deprecated => true
26
27
  def save(app)
27
28
  ssh = check_ssh_executable! options.ssh
28
29
  rest_app = find_app
30
+
31
+ raise RHC::DeploymentsNotSupportedException.new if options.deployment && !rest_app.supports?("DEPLOY")
32
+
29
33
  ssh_uri = URI.parse(rest_app.ssh_url)
30
34
  filename = options.filepath ? options.filepath : "#{rest_app.name}.tar.gz"
31
35
 
32
- ssh_cmd = "#{ssh} #{ssh_uri.user}@#{ssh_uri.host} 'snapshot' > #{filename}"
36
+ snapshot_cmd = options.deployment ? 'gear archive-deployment' : 'snapshot'
37
+ ssh_cmd = "#{ssh} #{ssh_uri.user}@#{ssh_uri.host} '#{snapshot_cmd}' > #{filename}"
33
38
  debug ssh_cmd
34
39
 
35
40
  say "Pulling down a snapshot to #{filename}..."
@@ -43,25 +43,40 @@ module RHC::Commands
43
43
  summary 'Add SSH key to your account'
44
44
  syntax '<name> <path to SSH key file>'
45
45
  argument :name, 'Name for this key', []
46
- argument :key, 'SSH public key filepath', []
46
+ argument :key, 'SSH public key filepath', [], :optional => true
47
47
  option ['--confirm'], 'Bypass key validation'
48
- def add(name, key)
49
- type, content, comment = ssh_key_triple_for(key)
50
-
51
- # validate the user input before sending it to the server
52
- begin
53
- Net::SSH::KeyFactory.load_data_public_key "#{type} #{content}"
54
- rescue NotImplementedError, OpenSSL::PKey::PKeyError, Net::SSH::Exception => e
55
- debug e.inspect
56
- if options.confirm
57
- warn 'The key you are uploading is not recognized. You may not be able to authenticate to your application through Git or SSH.'
58
- else
59
- raise ::RHC::KeyDataInvalidException.new("File '#{key}' does not appear to be a recognizable key file (#{e}). You may specify the '--confirm' flag to add the key anyway.")
48
+ option ['--type TYPE'], 'Provide the key type directly if no key file is given'
49
+ option ['--content CONTENT'], 'Provide the key content directly if no key file is given'
50
+ def add(name, key_path=nil)
51
+
52
+ if key_path
53
+ type, content, comment = ssh_key_triple_for(key_path)
54
+ elsif options[:type].present? and options[:content].present?
55
+ type = options[:type]
56
+ content = options[:content]
57
+ else
58
+ raise ArgumentError, "You must either provide a key file, or the key type and content"
59
+ end
60
+
61
+ if type == 'krb5-principal'
62
+ # TODO: validate krb5?
63
+ else
64
+ # validate the user input before sending it to the server
65
+ begin
66
+ Net::SSH::KeyFactory.load_data_public_key "#{type} #{content}"
67
+ rescue NotImplementedError, OpenSSL::PKey::PKeyError, Net::SSH::Exception => e
68
+ debug e.inspect
69
+ if options.confirm
70
+ warn 'The key you are uploading is not recognized. You may not be able to authenticate to your application through Git or SSH.'
71
+ else
72
+ raise ::RHC::KeyDataInvalidException.new("File '#{key_path}' does not appear to be a recognizable key file (#{e}). You may specify the '--confirm' flag to add the key anyway.") if key_path
73
+ raise ::RHC::KeyDataInvalidException.new("The provided type and content does not appear to be a recognizable key (#{e}). You may specify the '--confirm' flag to add the key anyway.")
74
+ end
60
75
  end
61
76
  end
62
77
 
63
78
  rest_client.add_key(name, content, type)
64
- results { say "SSH key #{key} has been added as '#{name}'" }
79
+ results { say key_path ? "SSH key #{key_path} has been added as '#{name}'" : "SSH key '#{name}' has been added" }
65
80
 
66
81
  0
67
82
  end
@@ -37,7 +37,7 @@ module RHC::Commands
37
37
  begin
38
38
  #Use ssh -t to tail the logs
39
39
  debug ssh_cmd
40
- ssh_ruby(host, uuid, remote_cmd)
40
+ ssh_ruby(host, uuid, remote_cmd, false, true)
41
41
  rescue
42
42
  warn "You can tail this application directly with:\n#{ssh_cmd}"
43
43
  raise
@@ -0,0 +1,88 @@
1
+ require 'rhc/ssh_helpers'
2
+
3
+ module RHC
4
+ module DeploymentHelpers
5
+
6
+ extend self
7
+
8
+ include RHC::SSHHelpers
9
+
10
+ protected
11
+
12
+ def deploy_artifact(rest_app, artifact, hot_deploy, force_clean_build)
13
+ File.file?(artifact) ?
14
+ deploy_local_file(rest_app, artifact, hot_deploy, force_clean_build) :
15
+ artifact =~ /^#{URI::regexp}$/ ?
16
+ deploy_file_from_url(rest_app, artifact, hot_deploy, force_clean_build) :
17
+ deploy_git_ref(rest_app, artifact, hot_deploy, force_clean_build)
18
+ end
19
+
20
+ def deploy_git_ref(rest_app, ref, hot_deploy, force_clean_build)
21
+ say "Deployment of git ref '#{ref}' in progress for application #{rest_app.name} ..."
22
+
23
+ ssh_url = URI(rest_app.ssh_url)
24
+ remote_cmd = "gear deploy #{ref}#{hot_deploy ? ' --hot-deploy' : ''}#{force_clean_build ? ' --force-clean-build' : ''}"
25
+
26
+ begin
27
+ ssh_ruby(ssh_url.host, ssh_url.user, remote_cmd)
28
+ success "Success"
29
+ rescue
30
+ ssh_cmd = "ssh -t #{ssh_url.user}@#{ssh_url.host} '#{remote_cmd}'"
31
+ warn "Error deploying git ref. You can try to deploy manually with:\n#{ssh_cmd}"
32
+ raise
33
+ end
34
+ end
35
+
36
+ def deploy_local_file(rest_app, filename, hot_deploy, force_clean_build)
37
+ filename = File.expand_path(filename)
38
+ say "Deployment of file '#{filename}' in progress for application #{rest_app.name} ..."
39
+
40
+ ssh_url = URI(rest_app.ssh_url)
41
+ remote_cmd = "oo-binary-deploy#{hot_deploy ? ' --hot-deploy' : ''}#{force_clean_build ? ' --force-clean-build' : ''}"
42
+
43
+ begin
44
+ ssh_send_file_ruby(ssh_url.host, ssh_url.user, remote_cmd, filename)
45
+ success "Success"
46
+ rescue
47
+ ssh_cmd = "ssh -t #{ssh_url.user}@#{ssh_url.host} '#{remote_cmd}'"
48
+ warn "Error deploying local file. You can try to deploy manually with:\n#{ssh_cmd}"
49
+ raise
50
+ end
51
+ end
52
+
53
+ def deploy_file_from_url(rest_app, file_url, hot_deploy, force_clean_build)
54
+ say "Deployment of file '#{file_url}' in progress for application #{rest_app.name} ..."
55
+
56
+ ssh_url = URI(rest_app.ssh_url)
57
+ file_url = URI(file_url)
58
+
59
+ remote_cmd = "oo-binary-deploy#{hot_deploy ? ' --hot-deploy' : ''}#{force_clean_build ? ' --force-clean-build' : ''}"
60
+
61
+ begin
62
+ ssh_send_url_ruby(ssh_url.host, ssh_url.user, remote_cmd, file_url)
63
+ success "Success"
64
+ rescue
65
+ ssh_cmd = "ssh -t #{ssh_url.user}@#{ssh_url.host} '#{remote_cmd}'"
66
+ warn "Error deploying file from url. You can try to deploy manually with:\n#{ssh_cmd}"
67
+ raise
68
+ end
69
+ end
70
+
71
+ def activate_deployment(rest_app, deployment_id)
72
+ say "Activating deployment '#{deployment_id}' on application #{rest_app.name} ..."
73
+
74
+ ssh_url = URI(rest_app.ssh_url)
75
+ remote_cmd = "gear activate #{deployment_id}"
76
+
77
+ begin
78
+ ssh_ruby(ssh_url.host, ssh_url.user, remote_cmd)
79
+ success "Success"
80
+ rescue
81
+ ssh_cmd = "ssh -t #{ssh_url.user}@#{ssh_url.host} '#{remote_cmd}'"
82
+ warn "Error activating deployment. You can try to activate manually with:\n#{ssh_cmd}"
83
+ raise
84
+ end
85
+ end
86
+
87
+ end
88
+ end