restfully-addons 1.0.0 → 1.1.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.
@@ -0,0 +1,205 @@
1
+ require 'rubygems'
2
+ require 'restfully'
3
+ require 'restfully/addons/bonfire'
4
+
5
+ CLIENT_IMAGE_NAME = "VM-iperf"
6
+ SERVER_IMAGE_NAME = "VM-iperf"
7
+ AGGREGATOR_IMAGE_NAME = "BonFIRE Zabbix Aggregator v4"
8
+ WAN_NAME = "BonFIRE WAN"
9
+
10
+ session = Restfully::Session.new(
11
+ :configuration_file => "~/.restfully/api.bonfire-project.eu",
12
+ :cache => false,
13
+ :gateway => "ssh.bonfire.grid5000.fr",
14
+ :keys => ["~/.ssh/id_rsa"],
15
+ :require => ["http://bonfire-dev.gforge.inria.fr/public/restfully/http.rb"]
16
+ )
17
+ session.logger.level = Logger::INFO
18
+
19
+ experiment = nil
20
+
21
+ begin
22
+ # Find an existing running experiment with the same name or submit a new
23
+ # one. This allows re-using an experiment when developing a new script.
24
+ experiment = session.root.experiments.find{|e|
25
+ e['name'] == "Demo ONE" && e['status'] == "running"
26
+ } || session.root.experiments.submit(
27
+ :name => "Demo ONE",
28
+ :description => "ONE demo using Restfully - #{Time.now.to_s}",
29
+ :status => "waiting",
30
+ :walltime => 8*3600 # 8 hours
31
+ )
32
+
33
+ # Create shortcuts for location resources:
34
+ inria = session.root.locations[:'fr-inria']
35
+ fail "Can't select the fr-inria location" if inria.nil?
36
+ hlrs = session.root.locations[:'de-hlrs']
37
+ fail "Can't select the de-hlrs location" if hlrs.nil?
38
+ epcc = session.root.locations[:'uk-epcc']
39
+ fail "Can't select the uk-epcc location" if epcc.nil?
40
+
41
+ # In this array we'll store the clients launched at each site:
42
+ locations = [[epcc,[]], [hlrs,[]], [inria,[]]]
43
+
44
+ session.logger.info "Launching aggregator..."
45
+ # Find an existing server in the experiment, or set up a new one:
46
+ aggregator = experiment.computes.find{|vm|
47
+ vm['name'] == "BonFIRE-monitor-experiment#{experiment['id']}"
48
+ } || experiment.computes.submit(
49
+ :name => "BonFIRE-monitor-experiment#{experiment['id']}",
50
+ :instance_type => "small",
51
+ :disk => [{
52
+ :storage => inria.storages.find{|s|
53
+ s['name'] == AGGREGATOR_IMAGE_NAME
54
+ }, :type => "OS"
55
+ }],
56
+ :nic => [{
57
+ :network => inria.networks.find{|n|
58
+ n['name'] == WAN_NAME
59
+ }
60
+ }],
61
+ :location => inria
62
+ )
63
+ aggregator_ip = aggregator['nic'][0]['ip']
64
+ session.logger.info "AGGREGATOR IP=#{aggregator_ip}"
65
+
66
+ session.logger.info "Launching server..."
67
+ # Find an existing server in the experiment, or set up a new one:
68
+ server = experiment.computes.find{|vm|
69
+ vm['name'] == "server-experiment#{experiment['id']}"
70
+ } || experiment.computes.submit(
71
+ :name => "server-experiment#{experiment['id']}",
72
+ :instance_type => "small",
73
+ :disk => [{
74
+ :storage => hlrs.storages.find{|s|
75
+ s['name'] == SERVER_IMAGE_NAME
76
+ },
77
+ :type => "OS"
78
+ }],
79
+ :nic => [
80
+ {:network => hlrs.networks.find{|n| n['name'] == WAN_NAME}}
81
+ ],
82
+ :location => hlrs,
83
+ :context => {
84
+ 'aggregator_ip' => aggregator_ip,
85
+ # Register metric on the server
86
+ 'metrics' => XML::Node.new_cdata('<metric>iperf.server-bw,fgrep ",-" /root/iperf_server_log.txt | cut -d "," -f9 | tail -1</metric>')
87
+ }
88
+ )
89
+ server_ip = server['nic'][0]['ip']
90
+ session.logger.info "SERVER IP=#{server_ip}"
91
+
92
+ # Procedure to create a client VM in a round-robin fashion on each location:
93
+ def create_client(session, experiment, locations, context = {})
94
+ # Sort locations by number of clients already running
95
+ placement = locations.sort{|loc1,loc2|
96
+ loc1[1].size <=> loc2[1].size
97
+ }.first
98
+ location, vms = placement
99
+ session.logger.info "Deploying client image on #{location['name']}..."
100
+ vms.push experiment.computes.submit(
101
+ :name => "#{location['name']}-#{vms.size}-client-e#{experiment['id']}",
102
+ :instance_type => "small",
103
+ :disk => [{
104
+ :storage => location.storages.find{|s|
105
+ s['name'] == CLIENT_IMAGE_NAME
106
+ }, :type => "OS"
107
+ }],
108
+ :nic => [
109
+ {:network => location.networks.find{|n| n['name'] == WAN_NAME}}
110
+ ],
111
+ :location => location,
112
+ :context => context.merge(
113
+ 'metrics' => XML::Node.new_cdata('<metric>iperf.client-bw,fgrep ",-" /root/iperf_clients_log.txt | cut -d "," -f9 | tail -1</metric>')
114
+ )
115
+ )
116
+ vms.last
117
+ end
118
+
119
+ # Select clients that were potentially already existing
120
+ # (in case of an experiment reuse).
121
+ locations.each do |(location,vms)|
122
+ vms.push(*location.computes.select{|vm|
123
+ vm['name'] =~ /client-e#{experiment['id']}$/
124
+ })
125
+ end
126
+ clients = locations.map{|(l,vms)| vms}.flatten
127
+
128
+ # Create two client if no existing clients:
129
+ clients = 2.times.map{ create_client(session, experiment, locations, {
130
+ 'aggregator_ip' => aggregator_ip,
131
+ 'iperf_server' => server_ip
132
+ })} if clients.empty?
133
+
134
+ # Pass the experiment status to running.
135
+ # If it was already running this has no effect.
136
+ experiment.update(:status => "running")
137
+
138
+ # Wait until all VMs are ACTIVE and ssh-able.
139
+ # Fail if one of them has FAILED.
140
+ until [aggregator, server, *clients].all?{|vm|
141
+ vm.reload['state'] == 'ACTIVE' && vm.ssh.accessible?
142
+ } do
143
+ fail "One of the VM has failed" if [aggregator, server, *clients].any?{|vm| vm['state'] == 'FAILED'}
144
+ session.logger.info "One of the VMs is not ready. Waiting..."
145
+ sleep 20
146
+ end
147
+
148
+ session.logger.info "VMs are now READY!"
149
+ # Display VM IPs
150
+ session.logger.info "*** Aggregator IP: #{aggregator_ip}"
151
+ session.logger.info "*** Server IP: #{server['nic'][0]['ip']}"
152
+ session.logger.info "*** Client IPs: #{clients.map{|vm| vm['nic'][0]['ip']}.inspect}"
153
+
154
+ # Control loop, until the experiment is done.
155
+ until ['terminated', 'canceled'].include?(experiment.reload['status']) do
156
+ case experiment['status']
157
+ when 'running'
158
+ session.logger.info "Experiment is running. Monitoring elasticity rule..."
159
+ session.logger.info "Clients: #{locations.map{|(l,vms)| "#{l['name']}: #{vms.map{|vm| vm['name']}.inspect}"}.join("; ")}."
160
+
161
+ # Check a metric values:
162
+ values = experiment.zabbix.metric('system.cpu.util[,system,avg1]', :type => :numeric, :hosts => server).values
163
+ avg3, avg5 = [values[0..3].avg, values[0..5].avg]
164
+
165
+ session.logger.info "Metric: values=#{values.inspect}, avg3=#{avg3}, avg5=#{avg5}."
166
+ clients_count = locations.map{|(l,vms)| vms}.flatten.length
167
+
168
+ # Here if the CPU usage of the iperf server is too low, we'll spawn a
169
+ # new client. If it's too high, we'll shut a client down.
170
+ if clients_count <= 10 && values.length >= 3 && avg3 <= 20
171
+ session.logger.warn "Scaling UP (avg=#{avg3})!"
172
+ vm = create_client(session, experiment, locations, {
173
+ 'aggregator_ip' => aggregator_ip,
174
+ 'iperf_server' => server_ip
175
+ })
176
+ sleep(10) until vm.ssh.accessible?
177
+ elsif clients_count > 1 && values.length >= 5 && avg5 >= 22
178
+ session.logger.warn "Scaling DOWN (avg=#{avg5})!"
179
+ # Delete the first client of the location which has the most clients:
180
+ locations.sort{|loc1,loc2|
181
+ loc2[1].size <=> loc1[1].size
182
+ }.first[1].shift.delete
183
+ else
184
+ session.logger.info "Nothing to do."
185
+ end
186
+
187
+ sleep 60
188
+ when 'terminating'
189
+ session.logger.info "Experiment is terminating. Here you could save images, retrieve data, etc."
190
+ sleep 30
191
+ else
192
+ session.logger.info "Experiment is #{experiment['status']}. Nothing to do yet."
193
+ sleep 60
194
+ end
195
+ end
196
+
197
+ session.logger.warn "Experiment terminated!"
198
+
199
+ rescue Exception => e
200
+ session.logger.error "#{e.class.name}: #{e.message}"
201
+ session.logger.error e.backtrace.join("\n")
202
+ session.logger.warn "Cleaning up in 30 seconds. Hit CTRL-C now to keep your VMs..."
203
+ sleep 30
204
+ experiment.delete unless experiment.nil?
205
+ end
@@ -0,0 +1,198 @@
1
+ require 'rubygems'
2
+ require 'restfully'
3
+ require 'restfully/addons/bonfire'
4
+
5
+ CLIENT_IMAGE_NAME = "BonFIRE Debian Squeeze 2G v2"
6
+ SERVER_IMAGE_NAME = "BonFIRE Debian Squeeze 2G v2"
7
+ AGGREGATOR_IMAGE_NAME = "BonFIRE Zabbix Aggregator v4"
8
+ WAN_NAME = "BonFIRE WAN"
9
+
10
+ session = Restfully::Session.new(
11
+ :configuration_file => "~/.restfully/api.bonfire-project.eu",
12
+ :cache => false,
13
+ :gateway => "ssh.bonfire.grid5000.fr",
14
+ :keys => ["~/.ssh/id_rsa"]
15
+ )
16
+ session.logger.level = Logger::INFO
17
+
18
+ experiment = nil
19
+
20
+ begin
21
+ # Find an existing running experiment with the same name or submit a new
22
+ # one. This allows re-using an experiment when developing a new script.
23
+ experiment = session.root.experiments.find{|e|
24
+ e['name'] == "Demo VW" && e['status'] == "running"
25
+ } || session.root.experiments.submit(
26
+ :name => "Demo VW",
27
+ :description => "VW demo using Restfully - #{Time.now.to_s}",
28
+ :status => "waiting",
29
+ :walltime => 8*3600 # 8 hours
30
+ )
31
+
32
+ # Create shortcuts for location resources:
33
+ inria = session.root.locations[:'fr-inria']
34
+ fail "Can't select the fr-inria location" if inria.nil?
35
+ ibbt = session.root.locations[:'be-ibbt']
36
+ fail "Can't select the de-hlrs location" if ibbt.nil?
37
+
38
+ # In this array we'll store the clients launched at each site:
39
+ locations = [[ibbt,[]]]
40
+
41
+ private_network = experiment.networks.submit(
42
+ :location => ibbt,
43
+ :name => "network-experiment#{experiment['id']}",
44
+ :bandwidth => 1000,
45
+ :latency => 0,
46
+ :size => 24,
47
+ :lossrate => 0,
48
+ # You MUST specify the address:
49
+ :address => "192.168.0.0"
50
+ )
51
+
52
+ session.logger.info "Launching aggregator..."
53
+ aggregator = experiment.computes.find{|vm|
54
+ vm['name'] == "BonFIRE-monitor-experiment#{experiment['id']}"
55
+ } || experiment.computes.submit(
56
+ :name => "BonFIRE-monitor-experiment#{experiment['id']}",
57
+ :instance_type => "small",
58
+ :disk => [
59
+ {
60
+ :storage => inria.storages.find{|s|
61
+ s['name'] == AGGREGATOR_IMAGE_NAME
62
+ },
63
+ :type => "OS"
64
+ }
65
+ ],
66
+ :nic => [
67
+ {
68
+ :network => inria.networks.find{|n|
69
+ n['name'] == WAN_NAME
70
+ }
71
+ }
72
+ ],
73
+ :location => inria
74
+ )
75
+ aggregator_ip = aggregator['nic'][0]['ip']
76
+ session.logger.info "AGGREGATOR IP=#{aggregator_ip}"
77
+
78
+ session.logger.info "Launching server..."
79
+ # Set up server
80
+ server = experiment.computes.find{|vm|
81
+ vm['name'] == "server-experiment#{experiment['id']}"
82
+ } || experiment.computes.submit(
83
+ :name => "server-experiment#{experiment['id']}",
84
+ :instance_type => "small",
85
+ :disk => [
86
+ {
87
+ :storage => ibbt.storages.find{|s|
88
+ s['name'] == SERVER_IMAGE_NAME
89
+ },
90
+ :type => "OS"
91
+ }
92
+ ],
93
+ :nic => [
94
+ {:network => ibbt.networks.find{|n| n['name'] == WAN_NAME}},
95
+ {:network => private_network, :ip => '192.168.0.2'}
96
+ ],
97
+ :location => ibbt,
98
+ :context => {
99
+ 'aggregator_ip' => aggregator_ip,
100
+ # Register metric on the server
101
+ 'metrics' => XML::Node.new_cdata('<metric>iperf.server-bw,fgrep ",-" /root/iperf_server_log.txt | cut -d "," -f9 | tail -1</metric>')
102
+ }
103
+ )
104
+ server_ip = server['nic'][0]['ip']
105
+ session.logger.info "SERVER IP=#{server_ip}"
106
+
107
+ # Procedure to create a client VM in a round-robin fashion on each location:
108
+ def create_client(session, experiment, locations, context = {})
109
+ # Sort locations by number of clients already running
110
+ placement = locations.sort{|loc1,loc2|
111
+ loc1[1].size <=> loc2[1].size
112
+ }.first
113
+ location, vms = placement
114
+ session.logger.info "Deploying client image on #{location['name']}..."
115
+ private_ip = "192.168.0.#{vms.size+3}"
116
+ vms.push experiment.computes.submit(
117
+ :name => "#{location['name']}-#{vms.size}-client-e#{experiment['id']}",
118
+ :instance_type => "small",
119
+ :disk => [
120
+ {
121
+ :storage => location.storages.find{|s|
122
+ s['name'] == CLIENT_IMAGE_NAME
123
+ },
124
+ :type => "OS"
125
+ }
126
+ ],
127
+ :nic => [
128
+ {:network => location.networks.find{|n| n['name'] == WAN_NAME}},
129
+ {:network => context.delete(:private_network), :ip => private_ip}
130
+ ],
131
+ :location => location,
132
+ :context => context.merge(
133
+ 'metrics' => XML::Node.new_cdata('<metric>iperf.client-bw,fgrep ",-" /root/iperf_clients_log.txt | cut -d "," -f9 | tail -1</metric>')
134
+ )
135
+ )
136
+ vms.last
137
+ end
138
+
139
+ # Select clients that were potentially already existing
140
+ # (in case of an experiment reuse).
141
+ locations.each do |(location,vms)|
142
+ vms.push(*location.computes.select{|vm|
143
+ vm['name'] =~ /client-e#{experiment['id']}$/
144
+ })
145
+ end
146
+ clients = locations.map{|(l,vms)| vms}.flatten
147
+
148
+ # Create two client if no existing clients:
149
+ clients = 2.times.map{ create_client(session, experiment, locations, {
150
+ 'aggregator_ip' => aggregator_ip,
151
+ 'iperf_server' => '192.168.0.2',
152
+ :private_network => private_network
153
+ })} if clients.empty?
154
+
155
+ # Pass the experiment status to running.
156
+ # If it was already running this has no effect.
157
+ experiment.update(:status => "running")
158
+
159
+ # Wait until all VMs are ACTIVE and ssh-able.
160
+ # Fail if one of them has FAILED.
161
+ until [aggregator, server, *clients].all?{|vm|
162
+ vm.reload['state'] == 'ACTIVE' && vm.ssh.accessible?
163
+ } do
164
+ fail "One of the VM has failed" if [aggregator, server, *clients].any?{|vm| vm['state'] == 'FAILED'}
165
+ session.logger.info "One of the VMs is not ready. Waiting..."
166
+ sleep 20
167
+ end
168
+
169
+ session.logger.info "VMs are now READY!"
170
+ # Display VM IPs
171
+ session.logger.info "*** Aggregator IP: #{aggregator_ip}"
172
+ session.logger.info "*** Server IP: #{server['nic'][0]['ip']}"
173
+ session.logger.info "*** Client IPs: #{clients.map{|vm| vm['nic'][0]['ip']}.inspect}"
174
+
175
+ # Control loop, until the experiment is done.
176
+ until ['terminated', 'canceled'].include?(experiment.reload['status']) do
177
+ case experiment['status']
178
+ when 'running'
179
+ session.logger.info "Experiment is running..."
180
+ sleep 60
181
+ when 'terminating'
182
+ session.logger.info "Experiment is terminating. Here you could save images, retrieve data, etc."
183
+ sleep 30
184
+ else
185
+ session.logger.info "Experiment is #{experiment['status']}. Nothing to do yet."
186
+ sleep 60
187
+ end
188
+ end
189
+
190
+ session.logger.warn "Experiment terminated!"
191
+
192
+ rescue Exception => e
193
+ session.logger.error "#{e.class.name}: #{e.message}"
194
+ session.logger.error e.backtrace.join("\n")
195
+ session.logger.warn "Cleaning up in 30 seconds. Hit CTRL-C now to keep your VMs..."
196
+ sleep 30
197
+ experiment.delete unless experiment.nil?
198
+ end
@@ -0,0 +1,107 @@
1
+ require 'rubygems'
2
+ require 'restfully'
3
+ require 'restfully/addons/bonfire'
4
+
5
+ SERVER_IMAGE_NAME = "BonFIRE Debian Squeeze v2"
6
+ WAN_NAME = "BonFIRE WAN"
7
+
8
+ logger = Logger.new(STDOUT)
9
+ logger.level = Logger::INFO
10
+
11
+ session = Restfully::Session.new(
12
+ :configuration_file => "~/.restfully/api.bonfire-project.eu",
13
+ :gateway => "ssh.bonfire.grid5000.fr",
14
+ :keys => ["~/.ssh/id_rsa"],
15
+ :cache => false,
16
+ :logger => logger
17
+ )
18
+
19
+ experiment = nil
20
+
21
+ begin
22
+ # Find an existing running experiment with the same name or submit a new
23
+ # one. This allows re-using an experiment when developing a new script.
24
+ experiment = session.root.experiments.find{|e|
25
+ e['name'] == "Demo SSH" && e['status'] == "running"
26
+ } || session.root.experiments.submit(
27
+ :name => "Demo SSH",
28
+ :description => "SSH demo using Restfully - #{Time.now.to_s}",
29
+ :status => "waiting",
30
+ :walltime => 8*3600 # 8 hours
31
+ )
32
+
33
+ # Create shortcuts for location resources:
34
+ inria = session.root.locations[:'fr-inria']
35
+ fail "Can't select the fr-inria location" if inria.nil?
36
+
37
+ session.logger.info "Launching VM..."
38
+ # Find an existing server in the experiment, or set up a new one:
39
+ server = experiment.computes.find{|vm|
40
+ vm['name'] == "VM-experiment#{experiment['id']}"
41
+ } || experiment.computes.submit(
42
+ :name => "VM-experiment#{experiment['id']}",
43
+ :instance_type => "small",
44
+ :disk => [{
45
+ :storage => inria.storages.find{|s|
46
+ s['name'] == SERVER_IMAGE_NAME
47
+ },
48
+ :type => "OS"
49
+ }],
50
+ :nic => [
51
+ {:network => inria.networks.find{|n| n['name'] == WAN_NAME}}
52
+ ],
53
+ :location => inria
54
+ )
55
+ server_ip = server['nic'][0]['ip']
56
+ session.logger.info "SERVER IP=#{server_ip}"
57
+
58
+ # Pass the experiment status to running.
59
+ # If it was already running this has no effect.
60
+ experiment.update(:status => "running")
61
+
62
+ # Wait until all VMs are ACTIVE and ssh-able.
63
+ # Fail if one of them has FAILED.
64
+ until [server].all?{|vm|
65
+ vm.reload['state'] == 'ACTIVE' && vm.ssh.accessible?
66
+ } do
67
+ fail "One of the VM has failed" if [server].any?{|vm|
68
+ vm['state'] == 'FAILED'
69
+ }
70
+ session.logger.info "One of the VMs is not ready. Waiting..."
71
+ sleep 20
72
+ end
73
+
74
+ session.logger.info "VMs are now READY!"
75
+ # Display VM IPs
76
+ session.logger.info "*** Server IP: #{server['nic'][0]['ip']}"
77
+
78
+ server.ssh do |ssh|
79
+ session.logger.info "Uploading content..."
80
+ # Here is how you would upload a file:
81
+ # ssh.scp.upload!("/path/to/file", '/tmp/file.log')
82
+ # Here is how you can upload some in-memory data:
83
+ ssh.scp.upload!(StringIO.new('some data'), '/tmp/file.log')
84
+ # See <http://net-ssh.github.com/scp/v1/api/index.html> for more details.
85
+
86
+ session.logger.info "Content of uploaded file:"
87
+ puts ssh.exec!("cat /tmp/file.log")
88
+
89
+ session.logger.info "Installing things..."
90
+ output = ssh.exec!("apt-get install curl -y")
91
+ session.logger.debug output
92
+
93
+ session.logger.info "Running query against API..."
94
+ puts ssh.exec!("source /etc/default/bonfire && curl -k $BONFIRE_URI/locations/$BONFIRE_PROVIDER/computes/$BONFIRE_RESOURCE_ID -u $BONFIRE_CREDENTIALS")
95
+ end
96
+
97
+ session.logger.warn "Success! Will delete experiment in 10 seconds. Hit CTRL-C now to keep your VMs..."
98
+ sleep 10
99
+ experiment.delete
100
+
101
+ rescue Exception => e
102
+ session.logger.error "#{e.class.name}: #{e.message}"
103
+ session.logger.error e.backtrace.join("\n")
104
+ session.logger.warn "Cleaning up in 30 seconds. Hit CTRL-C now to keep your VMs..."
105
+ sleep 30
106
+ experiment.delete unless experiment.nil?
107
+ end
@@ -4,11 +4,16 @@ require 'net/sftp'
4
4
 
5
5
  module Restfully
6
6
  class Resource
7
+ # Opens an SSH session on the resource's IP.
8
+ # Returns the result of the last statement of the given block.
7
9
  def ssh(user = nil, opts = {}, &block)
8
10
  raise NotImplementedError unless uri.to_s =~ /\/computes\/\w+$/
9
11
  @ssh ||= SSH.new(session, self)
10
- @ssh.run(@ssh.ip, user, opts, &block) if block
11
- @ssh
12
+ if block
13
+ @ssh.run(@ssh.ip, user, opts, &block)
14
+ else
15
+ @ssh
16
+ end
12
17
  end
13
18
  end
14
19
 
@@ -27,10 +32,18 @@ module Restfully
27
32
  gateway = session.config[:gateway]
28
33
  if gateway
29
34
  gateway_handler = Net::SSH::Gateway.new(gateway, session.config[:username], options)
30
- gateway_handler.ssh(fqdn, user, options, &block)
35
+ result = nil
36
+ gateway_handler.ssh(fqdn, user, options) {|handler|
37
+ result = block.call(handler)
38
+ }
31
39
  gateway_handler.shutdown!
40
+ result
32
41
  else
33
- Net::SSH.start(fqdn, user, options, &block)
42
+ result = nil
43
+ Net::SSH.start(fqdn, user, options) {|handler|
44
+ result = block.call(handler)
45
+ }
46
+ result
34
47
  end
35
48
  end
36
49
 
@@ -1,5 +1,5 @@
1
1
  module Restfully
2
2
  module Addons
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restfully-addons
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-29 00:00:00.000000000 +02:00
12
+ date: 2011-09-21 00:00:00.000000000 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: restfully
17
- requirement: &2156314120 !ruby/object:Gem::Requirement
17
+ requirement: &2153539680 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2156314120
25
+ version_requirements: *2153539680
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: net-ssh-gateway
28
- requirement: &2156313660 !ruby/object:Gem::Requirement
28
+ requirement: &2153570680 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *2156313660
36
+ version_requirements: *2153570680
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: net-scp
39
- requirement: &2156313240 !ruby/object:Gem::Requirement
39
+ requirement: &2153570260 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *2156313240
47
+ version_requirements: *2153570260
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: net-sftp
50
- requirement: &2156312820 !ruby/object:Gem::Requirement
50
+ requirement: &2153569840 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: '0'
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *2156312820
58
+ version_requirements: *2153569840
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: net-ssh-multi
61
- requirement: &2156312400 !ruby/object:Gem::Requirement
61
+ requirement: &2153569420 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: '0'
67
67
  type: :runtime
68
68
  prerelease: false
69
- version_requirements: *2156312400
69
+ version_requirements: *2153569420
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: libxml-ruby
72
- requirement: &2156311980 !ruby/object:Gem::Requirement
72
+ requirement: &2153569000 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ! '>='
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: '0'
78
78
  type: :runtime
79
79
  prerelease: false
80
- version_requirements: *2156311980
80
+ version_requirements: *2153569000
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: rake
83
- requirement: &2156563360 !ruby/object:Gem::Requirement
83
+ requirement: &2153568500 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ~>
@@ -88,7 +88,7 @@ dependencies:
88
88
  version: '0.8'
89
89
  type: :development
90
90
  prerelease: false
91
- version_requirements: *2156563360
91
+ version_requirements: *2153568500
92
92
  description: Addons for Restfully
93
93
  email:
94
94
  - cyril.rohr@inria.fr
@@ -103,6 +103,9 @@ files:
103
103
  - lib/restfully/addons/bonfire.rb
104
104
  - lib/restfully/addons/version.rb
105
105
  - lib/restfully/addons.rb
106
+ - examples/bonfire/scenario1.rb
107
+ - examples/bonfire/scenario2.rb
108
+ - examples/bonfire/ssh.rb
106
109
  - Rakefile
107
110
  - LICENSE
108
111
  - README.md