openstack_activeresource 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.document +5 -0
  2. data/Gemfile +15 -0
  3. data/Gemfile.lock +49 -0
  4. data/LICENSE.txt +14 -0
  5. data/README.rdoc +427 -0
  6. data/Rakefile +44 -0
  7. data/VERSION +1 -0
  8. data/lib/hot_fixes.rb +55 -0
  9. data/lib/locales/en.yml +5 -0
  10. data/lib/open_stack/base.rb +88 -0
  11. data/lib/open_stack/common.rb +56 -0
  12. data/lib/open_stack/glance/base.rb +39 -0
  13. data/lib/open_stack/glance/image.rb +33 -0
  14. data/lib/open_stack/glance.rb +27 -0
  15. data/lib/open_stack/keystone/admin/base.rb +41 -0
  16. data/lib/open_stack/keystone/admin/role.rb +35 -0
  17. data/lib/open_stack/keystone/admin/tenant.rb +104 -0
  18. data/lib/open_stack/keystone/admin/user.rb +98 -0
  19. data/lib/open_stack/keystone/admin/user_role.rb +34 -0
  20. data/lib/open_stack/keystone/admin.rb +32 -0
  21. data/lib/open_stack/keystone/public/auth.rb +141 -0
  22. data/lib/open_stack/keystone/public/base.rb +41 -0
  23. data/lib/open_stack/keystone/public/tenant.rb +64 -0
  24. data/lib/open_stack/keystone/public.rb +31 -0
  25. data/lib/open_stack/keystone.rb +27 -0
  26. data/lib/open_stack/nova/compute/base.rb +41 -0
  27. data/lib/open_stack/nova/compute/base_detail.rb +59 -0
  28. data/lib/open_stack/nova/compute/flavor.rb +56 -0
  29. data/lib/open_stack/nova/compute/floating_ip.rb +61 -0
  30. data/lib/open_stack/nova/compute/floating_ip_pool.rb +36 -0
  31. data/lib/open_stack/nova/compute/image.rb +76 -0
  32. data/lib/open_stack/nova/compute/key_pair.rb +47 -0
  33. data/lib/open_stack/nova/compute/network.rb +45 -0
  34. data/lib/open_stack/nova/compute/security_group.rb +117 -0
  35. data/lib/open_stack/nova/compute/server.rb +313 -0
  36. data/lib/open_stack/nova/compute/simple_tenant_usage.rb +128 -0
  37. data/lib/open_stack/nova/compute/volume_attachment.rb +98 -0
  38. data/lib/open_stack/nova/compute.rb +39 -0
  39. data/lib/open_stack/nova/volume/base.rb +41 -0
  40. data/lib/open_stack/nova/volume/volume.rb +77 -0
  41. data/lib/open_stack/nova/volume.rb +29 -0
  42. data/lib/open_stack/nova.rb +27 -0
  43. data/lib/open_stack.rb +40 -0
  44. data/lib/openstack_activeresource.rb +1 -0
  45. data/test/helper.rb +18 -0
  46. data/test/test_openstack-activeresource.rb +7 -0
  47. metadata +190 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source :rubygems
2
+
3
+ gem "activemodel", :require => 'active_model'
4
+ gem "activeresource", :require => 'active_resource'
5
+
6
+ gem "oj", "~> 1.2.9"
7
+
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.2.0"
12
+ gem "jeweler", "~> 1.8.4"
13
+ gem "simplecov", ">= 0"
14
+ end
15
+
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.6)
5
+ activesupport (= 3.2.6)
6
+ builder (~> 3.0.0)
7
+ activeresource (3.2.6)
8
+ activemodel (= 3.2.6)
9
+ activesupport (= 3.2.6)
10
+ activesupport (3.2.6)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ builder (3.0.0)
14
+ git (1.2.5)
15
+ i18n (0.6.0)
16
+ jeweler (1.8.4)
17
+ bundler (~> 1.0)
18
+ git (>= 1.2.5)
19
+ rake
20
+ rdoc
21
+ json (1.7.3)
22
+ multi_json (1.3.6)
23
+ oj (1.2.9)
24
+ rake (0.9.2.2)
25
+ rdoc (3.12)
26
+ json (~> 1.4)
27
+ shoulda (3.1.1)
28
+ shoulda-context (~> 1.0)
29
+ shoulda-matchers (~> 1.2)
30
+ shoulda-context (1.0.0)
31
+ shoulda-matchers (1.2.0)
32
+ activesupport (>= 3.0.0)
33
+ simplecov (0.6.4)
34
+ multi_json (~> 1.0)
35
+ simplecov-html (~> 0.5.3)
36
+ simplecov-html (0.5.3)
37
+
38
+ PLATFORMS
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ activemodel
43
+ activeresource
44
+ bundler (~> 1.2.0)
45
+ jeweler (~> 1.8.4)
46
+ oj (~> 1.2.9)
47
+ rdoc (~> 3.12)
48
+ shoulda
49
+ simplecov
data/LICENSE.txt ADDED
@@ -0,0 +1,14 @@
1
+ OpenStack-ActiveResource
2
+
3
+ This program is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 3 of the License, or
6
+ (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ You should have received a copy of the GNU General Public License
14
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/README.rdoc ADDED
@@ -0,0 +1,427 @@
1
+ = openstack_activeresource
2
+
3
+ OpenStack API Ruby bindings with ActiveResource
4
+
5
+ Supported API:
6
+ * Glance
7
+ * Keystone (admin and public)
8
+ * Nova
9
+
10
+ Tested on Folsom and Essex release.
11
+
12
+ == Installation
13
+
14
+ ~# gem install openstack_activeresource
15
+
16
+ == Sample usages
17
+
18
+ === List available tenants (require the 'admin' role)
19
+
20
+ require 'openstack_activeresource'
21
+
22
+ # Set Keystone Public API endpoint
23
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
24
+
25
+ # Authentication
26
+ auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"
27
+
28
+ # Set the auth token for next API requests
29
+ OpenStack::Base.token = auth.token
30
+
31
+ OpenStack::Keystone::Public::Tenant.all.each { |tenant|
32
+ printf "Name: %s (id: %s, enabled? %s) - %s\n",
33
+ tenant.name.center(15), tenant.id.center(20), tenant.enabled.to_s.center(6), tenant.description
34
+ }
35
+
36
+ === Creating a new tenant and a new user (require the 'admin' role)
37
+
38
+ require 'openstack_activeresource'
39
+
40
+ # Set Keystone Public and Admin API endpoints
41
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
42
+ OpenStack::Keystone::Admin::Base.site = "https://my.keystone.api.server:35357/v2.0/"
43
+
44
+ # Authentication
45
+ auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"
46
+
47
+ # Set the auth token for next API requests
48
+ OpenStack::Base.token = auth.token
49
+
50
+ # Create a new tenant
51
+ new_tenant = OpenStack::Keystone::Admin::Tenant.create :enabled => true, :name => "TestTenant", :description => "My new tenant"
52
+
53
+ # Create a new user in new_tenant
54
+ new_user = OpenStack::Keystone::Admin::User.create :tenant => new_tenant, :name => "TestUser", :password => "testpassword", :email => "test@user.com", :enabled => true
55
+
56
+ # Assign the "memberRole" in new_tenant to new_user
57
+ member_role = OpenStack::Keystone::Admin::Role.find_by_name "memberRole"
58
+ new_tenant.add_role_to_user member_role, new_user
59
+
60
+ === List image index from Nova
61
+
62
+ require 'openstack_activeresource'
63
+
64
+ # Set Keystone Public API endpoint
65
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
66
+
67
+ # Authentication
68
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
69
+
70
+ # Set the auth token for next API requests
71
+ OpenStack::Base.token = auth.token
72
+
73
+ # Set the Nova Compute API endpoint from the received service catalog
74
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
75
+
76
+ OpenStack::Nova::Compute::Image.all.each { |image|
77
+ printf "Name: %s (%s), minDisk: %3i, minRam: %5i, Status: %s, Progress: %3i\n",
78
+ image.name.center(40),
79
+ image.image_type.center(8),
80
+ image.min_disk || 0,
81
+ image.min_ram || 0,
82
+ image.status(7),
83
+ image.progress
84
+ }
85
+
86
+ === List virtual servers for a tenant
87
+
88
+ require 'openstack_activeresource'
89
+
90
+ # Set Keystone Public API endpoint
91
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
92
+
93
+ # Authentication
94
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
95
+
96
+ # Set the auth token for next API requests
97
+ OpenStack::Base.token = auth.token
98
+
99
+ # Set the Nova Compute API endpoint from the received service catalog
100
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
101
+
102
+ # Get all the servers
103
+ servers = OpenStack::Nova::Compute::Server.all
104
+
105
+ # To get only active server: OpenStack::Compute::Server.find :all, :params => {:status => "ACTIVE"}
106
+
107
+ servers.each { |s|
108
+ printf "Name: %s, Status: %s, Image: %s, Flavor: %s, Created: %s, Updated: %s\n",
109
+ s.name.center(20),
110
+ s.status.center(10),
111
+ s.image.id,
112
+ s.flavor.id,
113
+ s.created_at.to_time.localtime,
114
+ s.updated_at.to_time.localtime
115
+ }
116
+
117
+ === List available flavors
118
+
119
+ require 'openstack_activeresource'
120
+
121
+ # Set Keystone Public API endpoint
122
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
123
+
124
+ # Authentication
125
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
126
+
127
+ # Set the auth token for next API requests
128
+ OpenStack::Base.token = auth.token
129
+
130
+ # Set the Nova Compute API endpoint from the received service catalog
131
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
132
+
133
+ # Get available flavors
134
+ flavors = OpenStack::Nova::Compute::Flavor.all
135
+
136
+ flavors.each { |f|
137
+ printf "Name: %s, Id: %s, Ram: %5i, Disk: %3i (Ephemeral: %3i), vCPU: %2i\n", f.name.center(15), f.id.center(20), f.ram, f.disk, f.ephemeral_disk, f.vcpus
138
+ }
139
+
140
+ === Create a flavor (require 'admin' role)
141
+
142
+ require 'openstack_activeresource'
143
+
144
+ # Set Keystone Public API endpoint
145
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
146
+
147
+ # Authentication
148
+ auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"
149
+
150
+ # Set the auth token for next API requests
151
+ OpenStack::Base.token = auth.token
152
+
153
+ # Set the Nova Compute API endpoint from the received service catalog
154
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
155
+
156
+ # Create a flavor
157
+ flavors = OpenStack::Nova::Compute::Flavor.create :name => 'my_new_flavor', :ram => 1024, :disk => 20, :ephemeral_disk => 0
158
+
159
+ === List available security groups
160
+
161
+ require 'openstack_activeresource'
162
+
163
+ # Set Keystone Public API endpoint
164
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
165
+
166
+ # Authentication
167
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
168
+
169
+ # Set the auth token for next API requests
170
+ OpenStack::Base.token = auth.token
171
+
172
+ # Set the Nova Compute API endpoint from the received service catalog
173
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
174
+
175
+ # Get available security groups
176
+ security_groups = OpenStack::Nova::Compute::SecurityGroup.all
177
+
178
+ security_groups.each { |sg|
179
+ printf "Name: %s, Description: %s\n", sg.name.center(20), sg.description.center(50)
180
+
181
+ sg.rules.each { |r|
182
+ printf "Protocol: %s, From port: %5i, To port: %5i, Addresses: %s\n",
183
+ r.ip_protocol.center(4),
184
+ r.from_port,
185
+ r.to_port,
186
+ r.cidr.present? ? r.cidr.center(18) : ''.center(18)
187
+ }
188
+ puts "\n"
189
+ }
190
+
191
+ === List available Floating IPs
192
+
193
+ require 'openstack_activeresource'
194
+
195
+ # Set Keystone Public API endpoint
196
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
197
+
198
+ # Authentication
199
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
200
+
201
+ # Set the auth token for next API requests
202
+ OpenStack::Base.token = auth.token
203
+
204
+ # Set the Nova Compute API endpoint from the received service catalog
205
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
206
+
207
+ # Get available floating IPs
208
+ floatings = OpenStack::Nova::Compute::FloatingIp.all
209
+
210
+ floatings.each { |floating|
211
+ printf "IP: %s, Fixed IP: %s, Pool: %s, Instance: %s (%s)\n",
212
+ floating.ip.center(20),
213
+ floating.fixed_ip.present? ? floating.fixed_ip.center(20) : "".center(20),
214
+ floating.pool.center(20),
215
+ floating.instance_id.present? ? floating.instance_id.center(40) : "".center(40),
216
+ floating.instance.present? ? floating.instance.name.center(15) : "".center(15)
217
+
218
+ }
219
+
220
+ === Start a new virtual server and play with it
221
+
222
+ require 'openstack_activeresource'
223
+
224
+ # Set Keystone Public API endpoint
225
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
226
+
227
+ # Authentication
228
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
229
+
230
+ # Set the auth token for next API requests
231
+ OpenStack::Base.token = auth.token
232
+
233
+ # Set the Nova Compute API endpoint from the received service catalog
234
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
235
+
236
+ # Generate a new keypair
237
+ new_keypair = OpenStack::Nova::Compute::KeyPair.create :name => 'my_new_keypair'
238
+
239
+ # Prints out keypair info (!)
240
+ printf "Public key: %s\nPrivate key: %s\nKeypair Fingerprint: %s\n",
241
+ new_keypair.public_key,
242
+ new_keypair.private_key,
243
+ new_keypair.fingerprint
244
+
245
+ # Start a new virtual server
246
+ new_server = OpenStack::Nova::Compute::Server.create(
247
+ :name => 'my_new_server',
248
+ :flavor => OpenStack::Nova::Compute::Flavor.find_by_name('m1.tiny'),
249
+ :image => OpenStack::Nova::Compute::Image.find_by_name('Ubuntu Server 12.04 LTS amd64')
250
+ :key_pair => new_keypair,
251
+ :security_groups => OpenStack::Nova::Compute::SecurityGroup.all
252
+ )
253
+
254
+ # ... time passes...
255
+ sleep 5
256
+ # ... time passes...
257
+ new_server.refresh_status!
258
+ # Get server status
259
+ puts new_server.status
260
+
261
+ # Pause/unpause the server
262
+ new_server.pause
263
+ # ... time passes...
264
+ sleep 5
265
+ # ... time passes...
266
+ new_server.unpause
267
+
268
+ # Suspend/resume the server
269
+ new_server.suspend
270
+ # ... time passes...
271
+ sleep 5
272
+ # ... time passes...
273
+ new_server.resume
274
+
275
+ # Reboot the server
276
+ # new_server.reboot(:type => [:soft|:hard]) default :hard
277
+ new_server.reboot
278
+
279
+ # Get the server console output (last 10 row, default 50)
280
+ puts new_server.console_output(10)
281
+
282
+ # Get the server noVNC console URL
283
+ puts new_server.vnc_console
284
+
285
+ # ...code for floating IP retrieval... save the floating IP in my_floating_IP
286
+ # Add a floating IP to the server
287
+ new_server.add_floating_ip my_floating_IP
288
+
289
+ # ...code for volume retrieval... save the volume in my_volume
290
+ # Attach a volume to new_server
291
+ new_server.attach_volume! my_volume, '/dev/vdb'
292
+
293
+
294
+ === List available volumes
295
+
296
+ require 'openstack_activeresource'
297
+
298
+ # Set Keystone Public API endpoint
299
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
300
+
301
+ # Authentication
302
+ auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"
303
+
304
+ # Set the auth token for next API requests
305
+ OpenStack::Base.token = auth.token
306
+
307
+ # Set the Nova Volume API endpoint from the received service catalog
308
+ OpenStack::Nova::Volume::Base.site = auth.endpoint_for('volume').publicURL
309
+
310
+ # Get available volumes
311
+ volumes = OpenStack::Nova::Volume::Volume.all
312
+
313
+ volumes.each { |volume|
314
+ printf "Name: %s, Status: %s\n", volume.display_name.center(20), volume.status.center(50)
315
+ }
316
+
317
+ === Simple tenant usage (require 'admin' role)
318
+
319
+ require 'openstack_activeresource'
320
+
321
+ # Set Keystone Public and Admin API endpoints
322
+ OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
323
+
324
+ # Authentication
325
+ auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"
326
+
327
+ # Set the auth token for next API requests
328
+ OpenStack::Base.token = auth.token
329
+
330
+ # Set the Nova Compute API endpoint from the received service catalog
331
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
332
+
333
+ # Get the tenant
334
+ tenant = OpenStack::Keystone::Admin::Tenant.find_by_name "the_tenant"
335
+
336
+ # Get usage for a single tenant
337
+ simple_usage = OpenStack::Nova::Compute::SimpleTenantUsage.find tenant.id, :params => {:start => '1998-07-29T00:00:01', :end => '2012-07-09T00:00:00'}
338
+ # Or:
339
+ #past_month_start = (DateTime.now - 1.month).at_beginning_of_month
340
+ #past_month_end = (DateTime.now - 1.month).at_end_of_month
341
+ #simple_usage = OpenStack::Nova::Compute::SimpleTenantUsage.find_between_dates tenant.id, past_month_start, past_month_end
342
+
343
+ # get usage for all tenants
344
+ simple_usages = OpenStack::Nova::Compute::SimpleTenantUsage.find_from_date(:all, days.days.ago)
345
+
346
+ simple_usages.each { |usage|
347
+ printf "Tenant: %s, Total hours: %3.3f, Total memory: %8.3f, Total vcpus: %4.3f, Total disk: %5.3f\n",
348
+ usage.tenant_id.center(30),
349
+ usage.total_hours,
350
+ usage.total_memory_mb_usage,
351
+ usage.total_vcpus_usage,
352
+ usage.total_local_gb_usage
353
+
354
+ usage.server_usages.each { |su|
355
+ printf "\tName: %s, state: %s, vCPU: %2i, RAM: %5i, Disk: %3i, Started: %31s, Ended: %31s, Hours: %10.5f\n",
356
+ su.name.center(15),
357
+ su.state.center(15),
358
+ su.vcpus,
359
+ su.memory_mb,
360
+ su.local_gb,
361
+ su.started_at.to_time.localtime,
362
+ su.ended_at.nil? ? '' : su.ended_at.to_time.localtime,
363
+ su.hours
364
+ }
365
+ puts "\n"
366
+ }
367
+
368
+ == Using OpenStack-ActiveResource with Ruby on Rails (sample usage)
369
+
370
+ Create an helper method in your application controller
371
+
372
+ class ApplicationController < ActionController::Base
373
+
374
+ ...
375
+
376
+ private
377
+
378
+ def require_openstack_login
379
+ if OpenStack::Base.token.nil? or OpenStack::Base.token.expired?
380
+ OpenStack::Keystone::Public::Base.site = <keystone_public_api_uri>
381
+ # Admin API, if needed
382
+ OpenStack::Keystone::Admin::Base.site = <keystone_admin_api_uri>
383
+
384
+ auth = OpenStack::Keystone::Public::Auth.create :username => <username>, :password => <password>, :tenant_id => <tenant_id>
385
+
386
+ OpenStack::Base.token = auth.token
387
+
388
+ OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
389
+ # Set other endpoints if needed ...
390
+ # For instance:
391
+ # OpenStack::Nova::Volume::Base.site = auth.endpoint_for('volume').publicURL
392
+
393
+ end
394
+ end
395
+
396
+ ...
397
+
398
+ end
399
+
400
+ In controllers which need to access the openstack API,
401
+
402
+ class OpenStackConsumerController < ApplicationController
403
+
404
+ ...
405
+
406
+ # "Enable" openstack API only in methods where it is needed
407
+ before_filter :require_openstack_login, :only => [ :index, :show ]
408
+
409
+ ...
410
+
411
+ end
412
+
413
+ == Contributing to openstack_activeresource
414
+
415
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
416
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
417
+ * Fork the project.
418
+ * Start a feature/bugfix branch.
419
+ * Commit and push until you are happy with your contribution.
420
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
421
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
422
+
423
+ == Copyright
424
+
425
+ Copyright (c) 2012 Unidada S.p.A. (Davide Guerri - d.guerri@unidata.it). See LICENSE.txt for
426
+ further details.
427
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "openstack_activeresource"
18
+ gem.homepage = "http://github.com/dguerri/openstack_activeresource"
19
+ gem.license = "GPLv3"
20
+ gem.summary = %Q{OpenStack Ruby and RoR bindings implemented with ActiveResource}
21
+ gem.description = %Q{OpenStack Ruby and RoR bindings implemented with ActiveResource}
22
+ gem.email = "d.guerri@rd.unidata.it"
23
+ gem.authors = ["Davide Guerri"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ desc "Code coverage detail"
29
+ task :simplecov do
30
+ ENV['COVERAGE'] = "true"
31
+ Rake::Task['<%= test_task %>'].execute
32
+ end
33
+
34
+ task :default => :test
35
+
36
+ require 'rdoc/task'
37
+ Rake::RDocTask.new do |rdoc|
38
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
39
+
40
+ rdoc.rdoc_dir = 'rdoc'
41
+ rdoc.title = "OpenStack-ActiveResource #{version}"
42
+ rdoc.rdoc_files.include('README*')
43
+ rdoc.rdoc_files.include('lib/**/*.rb')
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/lib/hot_fixes.rb ADDED
@@ -0,0 +1,55 @@
1
+ # This file is part of the OpenStack-ActiveResource
2
+ #
3
+ # Copyright (C) 2012 Unidata S.p.A. (Davide Guerri - d.guerri@unidata.it)
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # Reopens ActiveResource::Base to fix "ActiveResource nested resources not being persisted"
19
+ # See https://github.com/rails/rails/pull/3107
20
+ module ActiveResource
21
+ class Base
22
+ def load(attributes, remove_root = false)
23
+ raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
24
+ @prefix_options, attributes = split_options(attributes)
25
+
26
+ if attributes.keys.size == 1
27
+ remove_root = self.class.element_name == attributes.keys.first.to_s
28
+ end
29
+
30
+ attributes = Formats.remove_root(attributes) if remove_root
31
+
32
+ attributes.each do |key, value|
33
+ @attributes[key.to_s] =
34
+ case value
35
+ when Array
36
+ resource = nil
37
+ value.map do |attrs|
38
+ if attrs.is_a?(Hash)
39
+ resource ||= find_or_create_resource_for_collection(key)
40
+ resource.new(attrs, attrs.has_key?(resource.primary_key.to_s))
41
+ else
42
+ attrs.duplicable? ? attrs.dup : attrs
43
+ end
44
+ end
45
+ when Hash
46
+ resource = find_or_create_resource_for(key)
47
+ resource.new(value, value.has_key?(resource.primary_key.to_s))
48
+ else
49
+ value.duplicable? ? value.dup : value
50
+ end
51
+ end
52
+ self
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ en:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ must_contain_at_least_one_digit_or_one_special_character: "must contain at least one digit or one special character"