restfully-addons 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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