gosen 0.1.7 → 0.2.0

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.
data/README.md CHANGED
@@ -5,13 +5,14 @@ It relies on the [Restfully library](http://github.com/crohr/restfully) for inte
5
5
 
6
6
  ## Features
7
7
 
8
- Currently, it allows to submit deployments that retry automatically when too many nodes failed, similarly to [Katapult](http://www.loria.fr/~lnussbau/katapult.html).
8
+ Currently, this library allows to submit deployments that retry automatically when too many nodes fail.
9
+ A clone of the [Katapult](http://www.loria.fr/~lnussbau/katapult.html) script, called Trebuchet, is also included and can be used on the command line.
9
10
 
10
11
  ## Installation
11
12
 
12
13
  $ gem install gosen
13
14
 
14
- ## Usage
15
+ ## Library Usage
15
16
 
16
17
  The following example deploys the latest version of the Lenny-x64-big environment on the paramount-1 and paramount-2 nodes.
17
18
  If both nodes are not successfully deployed, Gosen retries again (in this case, at most 5 deployment are submitted).
@@ -43,6 +44,24 @@ The logger allows to print information about the deployment, in a style similar
43
44
  I, [2010-04-21T11:37:11.817323 #21673] INFO -- : Nodes deployed: paramount-1.rennes.grid5000.fr paramount-2.rennes.grid5000.fr
44
45
  I, [2010-04-21T11:37:11.817440 #21673] INFO -- : Had to run 1 kadeploy runs, deployed 2 nodes
45
46
 
47
+ The Gosen specific options accepted by Gosen::Deployment.new() are:
48
+
49
+ * :logger, a Ruby Logger object,
50
+ * :min_deployed_nodes, the minimal number of successfully deployed nodes (defaults to 1),
51
+ * :max_deploy_runs, the maximal number of deploy runs to perform (defaults to 1),
52
+ * :continue_if_error, a boolean allowing to retry if a deployment returned with an error (defaults to false),
53
+ * :ssh_public_key, an SSH public key to be installed in the deployed environment.
54
+
55
+ It is also possible to pass options accepted by the [Deployments API](https://api.grid5000.fr/sid/deployments/help/index.html), such as version, block_device, partition_number, etc.
56
+
57
+ ## Script usage
58
+
59
+ Trebuchet was designed to be used like Katapult:
60
+
61
+ $ trebuchet -e lenny-x64-base --env-version 3 --min-deployed-nodes 4 --max-deploy-runs 2 -c
62
+
63
+ Run `trebuchet --help` to get usage information.
64
+
46
65
  ## Note on Patches/Pull Requests
47
66
 
48
67
  * Fork the project.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.7
1
+ 0.2.0
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gosen'
4
+ require 'logger'
5
+ require 'optparse'
6
+ require 'ostruct'
7
+
8
+ trap('INT') {
9
+ deployment_resource = @deployment.deployment_resource rescue nil
10
+ if deployment_resource && deployment_resource['status'] == 'processing'
11
+ deployment_resource.delete
12
+ puts "Cancelled deployment #{deployment_resource['uid']}"
13
+ end
14
+ exit
15
+ }
16
+
17
+ config = OpenStruct.new
18
+ deployment_options = {}
19
+ config.nodes = []
20
+
21
+ logger = Logger.new(STDOUT)
22
+ logger.level = Logger::INFO
23
+ deployment_options[:logger] = logger
24
+
25
+ options = OptionParser.new do |opts|
26
+ opts.banner = 'Usage: trebuchet [options]'
27
+ opts.separator ''
28
+ opts.separator 'Specific options:'
29
+ opts.on('-b', '--block-device BLOCKDEVICE', 'Specify the block device to use') do |p|
30
+ deployment_options[:block_device] = p
31
+ end
32
+ opts.on('-c', '--copy-ssh-key', 'Copy SSH keys to nodes') do
33
+ config.copy_ssh_key = true
34
+ end
35
+ opts.on('--disable_bootloader_install', 'Disable the automatic installation of a bootloader for a Linux based environnment') do
36
+ deployment_options[:disable_bootloader_install] = true
37
+ end
38
+ opts.on('--disable_disk_partitioning', 'Disable the disk partitioning') do
39
+ deployment_options[:disable_disk_partitioning] = true
40
+ end
41
+ opts.on('-e', '--deploy-env ENV', 'Environment to deploy') do |env|
42
+ config.deploy_env = env
43
+ end
44
+ opts.on('--env-version NUMBER', 'Number of version of the environment to deploy') do |v|
45
+ deployment_options[:version] = v
46
+ end
47
+ opts.on('-f', '--file MACHINELIST', 'Files containing the list of nodes') do |f|
48
+ config.nodefile = f
49
+ end
50
+ opts.on('-i', '--ssh-key-file FILE', "File containing keys to copy (defaults to #{config.ssh_keyfile})") do |f|
51
+ config.ssh_keyfile = f
52
+ end
53
+ opts.on('--ignore-nodes-deploying', 'Allow to deploy even on the nodes tagged as "currently deploying" (use this only if you know what you do)') do
54
+ deployment_options[:ignore_nodes_deploying] = true
55
+ end
56
+ opts.on('-l', '--deploy-user USER', 'User owning the deployment environment') do |u|
57
+ config.deploy_user = u
58
+ end
59
+ opts.on('-m', '--machine MACHINE', 'Node to run on') do |n|
60
+ config.nodes << n
61
+ end
62
+ opts.on('--max-deploy-runs NB', 'Maximum number of deployment runs before we admit we cannot get enough nodes deployed') do |n|
63
+ deployment_options[:max_deploy_runs] = n.to_i
64
+ end
65
+ opts.on('--min-deployed-nodes NB', 'Minimum number of nodes that must be correctly deployed before continuing') do |n|
66
+ deployment_options[:min_deployed_nodes] = n.to_i
67
+ end
68
+ opts.on('-p', '--partition-number NUMBER', 'Specify the partition number to use') do |p|
69
+ deployment_options[:partition_number] = p
70
+ end
71
+ opts.on('-r', '--reformat-tmp FSTYPE', 'Reformat the /tmp partition') do |fs|
72
+ fstypes = [ "ext2", "ext3", "ext4" ]
73
+ abort "FSTYPE must be one of #{fstypes.join(', ')}" unless fstypes.include?(fs)
74
+ deployment_options[:reformat_tmp] = fs
75
+ end
76
+ end
77
+
78
+ begin
79
+ options.parse!(ARGV)
80
+ rescue OptionParser::ParseError => e
81
+ $stderr.puts e
82
+ exit 1
83
+ end
84
+
85
+ if config.nodes.empty?
86
+ config.nodefile ||= ENV['OAR_NODEFILE']
87
+ config.nodes = File.open(File.expand_path(config.nodefile)).readlines.collect { |l| l.chomp }.sort.uniq
88
+ end
89
+
90
+ if config.nodes.empty?
91
+ abort "No nodes specified, and no OAR_NODEFILE variable, exiting.\nRun trebuchet --help if you need help."
92
+ end
93
+
94
+ if config.deploy_env.nil?
95
+ abort "Error: an environment to deploy is required.\nRun trebuchet --help if you need help."
96
+ end
97
+
98
+ if config.deploy_user
99
+ config.deploy_env += "@#{config.deploy_user}"
100
+ end
101
+
102
+ if config.ssh_keyfile
103
+ abort 'Error: the --ssh-keyfile option only makes sense with --copy-ssh-key.\nRun trebuchet --help if you need help.' if config.copy_ssh_key.nil?
104
+ end
105
+
106
+ if config.copy_ssh_key
107
+ config.ssh_keyfile ||= '~/.ssh/authorized_keys'
108
+ deployment_options[:ssh_public_key] = File.open(File.expand_path(config.ssh_keyfile)).read
109
+ end
110
+
111
+ if ENV['RESTFULLY_CONFIG'].nil?
112
+ abort "No RESTFULLY_CONFIG environment variable, exiting.\nRun trebuchet --help if you need help."
113
+ end
114
+
115
+ Restfully::Session.new({ :configuration_file => ENV['RESTFULLY_CONFIG'] }) do |grid, session|
116
+ indexed_nodes = Gosen::index_nodes_by_site(config.nodes)
117
+ if indexed_nodes.keys.length > 1
118
+ raise StandardError.new("The node list needs to be specific to a single site\nRun trebuchet --help if you need help.")
119
+ end
120
+ site = grid.sites[indexed_nodes.keys.first.to_sym].load
121
+ @deployment = Gosen::Deployment.new(site, config.deploy_env, config.nodes, deployment_options)
122
+ @deployment.join
123
+ end
@@ -4,7 +4,7 @@ require 'gosen/deployment'
4
4
  require 'gosen/error'
5
5
 
6
6
  module Gosen
7
- VERSION = "0.1.7"
7
+ VERSION = "0.2.0"
8
8
 
9
9
  # Extracts the site part of a Grid'5000 node hostname, and returns a hash indexing the nodes by their site
10
10
  # Example:
@@ -80,6 +80,10 @@ module Gosen
80
80
  raise Gosen::Error.new("Not enough nodes deployed after #{@max_deploy_runs} deployment(s): needed #{@min_deployed_nodes} nodes, got only #{@good_nodes.length}")
81
81
  end
82
82
 
83
+ def deployment_resource
84
+ @deployment_run.deployment_resource rescue nil
85
+ end
86
+
83
87
  def no_more_required?
84
88
  @good_nodes.length >= @min_deployed_nodes
85
89
  end
@@ -126,6 +126,23 @@ class TestDeployment < Test::Unit::TestCase
126
126
  @deployment_resource.stubs(:[]).with('status').returns('processing', 'processing', 'terminated')
127
127
  end
128
128
 
129
+ should 'have a reader on the deployment resource' do
130
+ @deployment_result = {
131
+ 'paramount-1.rennes.grid5000.fr' => { 'state' => 'OK' },
132
+ 'paramount-2.rennes.grid5000.fr' => { 'state' => 'OK' }
133
+ }
134
+ @deployment_resource.expects(:[]).with('result').returns(@deployment_result)
135
+ @site_deployments.expects(:submit).with({ :environment => @environment, :nodes => @nodes }).returns(@deployment_resource)
136
+ @min_deployed_nodes = 2
137
+ @logger.expects(:info).with("Kadeploy run 1 with #{@nodes.length} nodes (0 already deployed, need #{@min_deployed_nodes} more)")
138
+ @logger.expects(:info).with("Nodes deployed: paramount-1.rennes.grid5000.fr paramount-2.rennes.grid5000.fr")
139
+ @logger.expects(:info).with("Had to run 1 kadeploy runs, deployed #{@deployment_result.length} nodes")
140
+
141
+ @deployment = Gosen::Deployment.new(@site, @environment, @nodes, { :logger => @logger, :min_deployed_nodes => @min_deployed_nodes })
142
+ @deployment.join
143
+ assert_equal(@deployment_resource, @deployment.deployment_resource)
144
+ end
145
+
129
146
  should 'submit a deployment run and wait for the result' do
130
147
  @deployment_result = {
131
148
  'paramount-1.rennes.grid5000.fr' => { 'state' => 'OK' },
@@ -81,6 +81,11 @@ class TestDeploymentRun < Test::Unit::TestCase
81
81
  @deployment = Gosen::DeploymentRun.new(@site, @environment, @nodes, { :ssh_public_key => @ssh_public_key })
82
82
  end
83
83
 
84
+ should 'have a reader on the deployment resource' do
85
+ @deployment.join
86
+ assert_equal(@resource, @deployment.deployment_resource)
87
+ end
88
+
84
89
  should 'wait for deployment completion and give access to the results' do
85
90
  assert_nothing_raised(Exception) {
86
91
  @deployment.join
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 7
9
- version: 0.1.7
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Pierre Riteau
@@ -14,8 +14,8 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-26 00:00:00 +02:00
18
- default_executable:
17
+ date: 2010-10-28 00:00:00 +02:00
18
+ default_executable: trebuchet
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: restfully
@@ -64,8 +64,8 @@ dependencies:
64
64
  version_requirements: *id003
65
65
  description: Gosen is a Ruby library providing high-level operations using the Grid'5000 RESTful API, such as Kadeploy deployments.
66
66
  email: priteau@gmail.com
67
- executables: []
68
-
67
+ executables:
68
+ - trebuchet
69
69
  extensions: []
70
70
 
71
71
  extra_rdoc_files:
@@ -78,6 +78,7 @@ files:
78
78
  - README.md
79
79
  - Rakefile
80
80
  - VERSION
81
+ - bin/trebuchet
81
82
  - lib/gosen.rb
82
83
  - lib/gosen/deployment.rb
83
84
  - lib/gosen/deployment_run.rb