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
@@ -0,0 +1,45 @@
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
+ module OpenStack
19
+ module Nova
20
+ module Compute
21
+
22
+ class Network < Base
23
+ self.collection_name = "os-networks"
24
+
25
+ schema do
26
+ attribute :bridge, :string
27
+ attribute :bridge_interface, :string
28
+ attribute :cidr, :string
29
+ attribute :label, :string
30
+ attribute :multi_host, :boolean
31
+ attribute :vlan, :integer
32
+ attribute :project_id, :string
33
+ end
34
+
35
+ validates :bridge, :format => {:with => /\A[a-z][a-z0-9]{1,8}\Z/i}
36
+ validates :bridge_interface, :format => {:with => /\A[a-z]{1,5}[a-z0-9]{1,5}(\.[0-9]{1,4})?\Z/i}
37
+ validates :cidr, :presence => true
38
+ validates :label, :presence => true, :format => {:with => /\A[\w\s\d]{1,20}\Z/i}
39
+ validates :vlan, :presence => true, :numericality => {:greater_than_or_equal_to => 2, :less_than_or_equal_to => 4096}
40
+
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,117 @@
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
+ module OpenStack
19
+ module Nova
20
+ module Compute
21
+
22
+ class SecurityGroup < Base
23
+ self.element_name = "os-security-group"
24
+ self.collection_name = "os-security-groups"
25
+
26
+ schema do
27
+ attribute :tenant_id, :string
28
+ attribute :name, :string
29
+ attribute :description, :string
30
+ end
31
+
32
+ validates :name, :presence => true
33
+ validates :description, :presence => true
34
+
35
+ end
36
+
37
+ class SecurityGroup::Rule < Base
38
+ self.element_name = "os-security-group-rule"
39
+ self.collection_name = "os-security-group-rules"
40
+
41
+ schema do
42
+ attribute :ip_protocol, :string
43
+ attribute :from_port, :integer
44
+ attribute :to_port, :integer
45
+ attribute :parent_group_id, :string
46
+ attribute :cidr, :string
47
+ end
48
+
49
+ validates :ip_protocol, :presence => true, :inclusion => {:in => %w(tcp udp icmp)}
50
+ validates :cidr, :presence => true, :format => {:with => OpenStack::IPV4_CIDR_REGEX}
51
+ validates :parent_group_id, :presence => true
52
+ validates :from_port, :presence => true, :numericality => {:only_integer => true}
53
+ validates :to_port, :presence => true, :numericality => {:only_integer => true}
54
+
55
+ validates_numericality_of :from_port, :less_than_or_equal_to => 255, :greater_than_or_equal_to => -1, :if => Proc.new { |rule| rule.icmp? }
56
+ validates_numericality_of :from_port, :less_than_or_equal_to => 65535, :greater_than_or_equal_to => 1, :if => Proc.new { |rule| rule.udp? or rule.tcp? }
57
+
58
+ validates_numericality_of :to_port, :less_than_or_equal_to => 255, :greater_than_or_equal_to => -1, :if => Proc.new { |rule| rule.icmp? }
59
+ validates_numericality_of :to_port, :less_than_or_equal_to => 65535, :greater_than_or_equal_to => 1, :if => Proc.new { |rule| rule.udp? or rule.tcp? }
60
+ validates_numericality_of :to_port, :greater_than_or_equal_to => :from_port, :if => Proc.new { |rule| rule.udp? or rule.tcp? }
61
+
62
+
63
+ def initialize(attributes = {}, persisted = false)
64
+ attributes = attributes.with_indifferent_access
65
+ new_attributes = {
66
+ :id => attributes[:id],
67
+ :ip_protocol => attributes[:ip_protocol],
68
+ :from_port => attributes[:from_port],
69
+ :to_port => attributes[:to_port],
70
+ :cidr => attributes[:cidr] || attributes[:ip_range][:cidr],
71
+ :parent_group_id => attributes[:parent_group].present? ? attributes[:parent_group].id : nil
72
+ }
73
+ super(new_attributes, persisted)
74
+ end
75
+
76
+ # Overload ActiveRecord::encode method
77
+ # Custom encoding to deal with openstack API
78
+ def encode(options={})
79
+ to_encode = {
80
+ :security_group_rule => {
81
+ :ip_protocol => ip_protocol,
82
+ :from_port => from_port,
83
+ :to_port => to_port,
84
+ :cidr => cidr,
85
+ :parent_group_id => parent_group_id,
86
+ }
87
+ }
88
+ to_encode.send("to_#{self.class.format.extension}", options)
89
+ end
90
+
91
+ def parent_group=(group)
92
+ parent_group_id = group.id
93
+ end
94
+
95
+ def parent_group
96
+ return nil if parent_group_id.nil?
97
+ SecurityGroup.find(parent_group_id)
98
+ end
99
+
100
+ def icmp?
101
+ ip_protocol == 'icmp'
102
+ end
103
+
104
+ def udp?
105
+ ip_protocol == 'udp'
106
+ end
107
+
108
+ def tcp?
109
+ ip_protocol == 'tcp'
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+ end
116
+ end
117
+
@@ -0,0 +1,313 @@
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
+ module OpenStack
19
+ module Nova
20
+ module Compute
21
+
22
+ class Server < BaseDetail
23
+
24
+ schema do
25
+ attribute :name, :string
26
+ attribute :status, :string
27
+ attribute :updated_at, :datetime
28
+ attribute :created_at, :datetime
29
+ attribute :vm_state, :string
30
+ attribute :task, :string
31
+ attribute :power_state, :integer
32
+ attribute :host_id, :string
33
+ attribute :tenant_id, :string
34
+ attribute :user_id, :string
35
+ attribute :image_id, :string
36
+ attribute :flavor_id, :string
37
+ attribute :key_pair_id, :string
38
+ end
39
+
40
+ validates :name, :format => {:with => /\A[\w\.\-\_]{2,}\Z/}, :length => {:maximum => 255}
41
+ validates :image, :presence => true
42
+ validates :flavor, :presence => true
43
+
44
+ def self.all_by_tenant(tenant)
45
+ tenant_id = tenant.is_a?(OpenStack::Keystone::Admin::Tenant) ? tenant.id : tenant
46
+
47
+ find(:all, :params => {:tenant_id => tenant_id})
48
+ end
49
+
50
+ def initialize(attributes = {}, persisted = false)
51
+ attributes = attributes.with_indifferent_access
52
+ new_attributes = {
53
+ :id => attributes[:id],
54
+ :name => attributes[:name],
55
+ :status => attributes[:status],
56
+ :updated_at => attributes[:updated].present? ? DateTime.strptime(attributes[:updated], OpenStack::DATETIME_FORMAT) : nil,
57
+ :created_at => attributes[:created].present? ? DateTime.strptime(attributes[:created], OpenStack::DATETIME_FORMAT) : nil,
58
+ :vm_state => attributes[:'OS-EXT-STS:vm_state'],
59
+ :task => attributes[:'OS-EXT-STS:task_state'],
60
+ :power_state => attributes['OS-EXT-STS:power_state'],
61
+ :host_id => attributes[:hostId],
62
+ :user_data => attributes[:user_data],
63
+ # :tenant_id => attributes[:tenant_id],
64
+ # :user_id => attributes[:user_id],
65
+ :addresses => attributes[:addresses] || []
66
+ }
67
+
68
+ if attributes[:key_pair].present?
69
+ new_attributes[:key_pair_id] = attributes[:key_pair].name
70
+ else
71
+ new_attributes[:key_pair_id] = attributes[:key_name]
72
+ end
73
+
74
+ if attributes[:image].present?
75
+ new_attributes[:image_id] = attributes[:image].is_a?(Image) ? attributes[:image].id : attributes[:image][:id]
76
+ elsif attributes[:image_id].present?
77
+ new_attributes[:image_id] = attributes[:image_id]
78
+ end
79
+
80
+ if attributes[:flavor].present?
81
+ new_attributes[:flavor_id] = attributes[:flavor].is_a?(Flavor) ? attributes[:flavor].id : attributes[:flavor][:id]
82
+ elsif attributes[:flavor_id].present?
83
+ new_attributes[:flavor_id] = attributes[:flavor_id]
84
+ end
85
+
86
+ super(new_attributes, persisted)
87
+
88
+ @attributes[:security_group_ids] = get_security_group_ids(attributes[:security_groups])
89
+
90
+ self
91
+ end
92
+
93
+ # Overload ActiveRecord::encode method
94
+ # Custom encoding to deal with openstack API
95
+ def encode(options={})
96
+ to_encode = {
97
+ :server => {
98
+ :name => name,
99
+ :imageRef => image_id,
100
+ :flavorRef => flavor_id,
101
+ }
102
+ }
103
+
104
+ # Optional attributes (openstack will not accept empty attribute for update/create)
105
+ to_encode[:server][:user_data] = Base64.encode64(user_data) if user_data.present?
106
+ to_encode[:server][:key_name] = key_pair_id if key_pair_id.present?
107
+ to_encode[:server][:security_groups] = get_security_groups.map { |sg| {:name => sg.name} } || []
108
+
109
+ to_encode.send("to_#{self.class.format.extension}", options)
110
+ end
111
+
112
+ # Accessors
113
+
114
+ def image
115
+ Image.find(image_id) if image_id.present?
116
+ end
117
+
118
+ def image=(image)
119
+ self.image_id = image.id
120
+ end
121
+
122
+ def flavor
123
+ Flavor.find(flavor_id) if flavor_id.present?
124
+ end
125
+
126
+ def flavor=(flavor)
127
+ self.flavor_id = flavor.id
128
+ end
129
+
130
+ def key_pair
131
+ KeyPair.find(key_pair_id) if key_pair_id.present?
132
+ end
133
+
134
+ def key_pair=(key_pair)
135
+ self.key_pair_id = key_pair.name
136
+ end
137
+
138
+ def security_groups
139
+ get_security_groups
140
+ end
141
+
142
+ def security_groups=(security_groups)
143
+ return if persisted? # Do Nothing (it's a read-only attribute for OpenStack)
144
+
145
+ @attributes[:security_group_ids] = get_security_group_ids(security_groups)
146
+ end
147
+
148
+ def addresses
149
+ addresses = {}
150
+ if persisted?
151
+ response = get('ips')
152
+ response.each { |net, address|
153
+ addresses[net] = address
154
+ }
155
+ else
156
+ attributes[:addresses]
157
+ end
158
+ end
159
+
160
+ def addresses=(something)
161
+ # Do Nothing (it's a read-only attribute for OpenStack)
162
+ end
163
+
164
+ def volume_attachments(scope = :all)
165
+ VolumeAttachment.find(scope, :params => {:server_id => self.id})
166
+ end
167
+
168
+ # Misc...
169
+
170
+ # Return the list of attached volumes
171
+ def attached_volumes
172
+ volume_attachments.present? ? volume_attachments.map { |va| va.volume } : []
173
+ end
174
+
175
+ # Attach a volume
176
+ def attach_volume!(volume, device_name)
177
+ VolumeAttachment.create(:volume => volume, :device => device_name, :server => self)
178
+ end
179
+
180
+ # Refresh server status
181
+ def refresh_status!
182
+ updated = Server.find(self.id)
183
+ self.progress = updated.progress
184
+ self.status = updated.status
185
+ self.task = updated.task
186
+
187
+ self
188
+ end
189
+
190
+ SERVER_STATUSES = {
191
+ :ACTIVE => I18n.t(:active),
192
+ :BUILD => I18n.t(:builing),
193
+ :DELETED => I18n.t(:deleted),
194
+ :ERROR => I18n.t(:in_error),
195
+ :HARD_REBOOT => I18n.t(:hard_rebooting),
196
+ :PASSWORD => I18n.t(:resetting_password),
197
+ :REBOOT => I18n.t(:soft_rebooting),
198
+ :REBUILD => I18n.t(:rebuilding_from_image),
199
+ :RESCUE => I18n.t(:in_rescue_mode),
200
+ :RESIZE => I18n.t(:resizing),
201
+ :REVERT_RESIZE => I18n.t(:revert_resizing),
202
+ :SHUTOFF => I18n.t(:user_powered_down),
203
+ :SUSPENDED => I18n.t(:suspended),
204
+ :PAUSED => I18n.t(:paused),
205
+ :UNKNOWN => I18n.t(:unknown),
206
+ :VERIFY_RESIZE => I18n.t(:awaiting_verification)
207
+ }.with_indifferent_access
208
+
209
+ # Returns an extended description for the server status
210
+ def status_description
211
+ SERVER_STATUSES[status]
212
+ end
213
+
214
+ ## Actions
215
+
216
+ # Assign a floating IP to the server.
217
+ # Params:
218
+ # +floating_ip+:: a FloatingIP to be attached to the server.
219
+ def add_floating_ip(floating_ip)
220
+ post(:action, {}, {:addFloatingIp => {:address => floating_ip.ip}}.to_json)
221
+ end
222
+
223
+ # Reboot the server.
224
+ # Params:
225
+ # +type+:: type of reboot. Should be 'hard' or 'soft' (defaults to 'hard', may be nil)
226
+ def reboot(type=:hard)
227
+ post(:action, {}, {:reboot => {:type => type}}.to_json)
228
+ end
229
+
230
+ # Creates a new snapshot of server.
231
+ # Params:
232
+ # +name+:: name of the new snapshot image
233
+ # +metadata+:: hash of metadata (may be nil)
234
+ def create_new_image(name, metadata={})
235
+ post(:action, {}, {:createImage => {:name => name, :metadata => metadata}}.to_json)
236
+ end
237
+
238
+ # Gets the output from the console log for a server.
239
+ # Params:
240
+ # +length+:: numbers of lines to get (defaults to 50, may be nil)
241
+ def console_output(length=50)
242
+ response = post(:action, {}, {:'os-getConsoleOutput' => {:length => length}}.to_json)
243
+
244
+ ActiveSupport::JSON.decode(response.body)['output']
245
+ end
246
+
247
+ # Accesses a VNC console for a specific server.
248
+ # Params:
249
+ # +length+:: numbers of lines to get (defaults to 50, may be nil)
250
+ def vnc_console(type='novnc')
251
+ response = post(:action, {}, {:'os-getVNCConsole' => {:type => type}}.to_json)
252
+
253
+ ActiveSupport::JSON.decode(response.body)['console']['url']
254
+ end
255
+
256
+ # Halts a running server. Changes status to STOPPED.
257
+ def stop
258
+ post(:action, {}, {:'os-stop' => nil}.to_json)
259
+ end
260
+
261
+ # Returns a STOPPED server to ACTIVE status.
262
+ def start
263
+ post(:action, {}, {:'os-start' => nil}.to_json)
264
+ end
265
+
266
+ # PAUSE a server.
267
+ def pause
268
+ post(:action, {}, {:'pause' => nil}.to_json)
269
+ end
270
+
271
+ # Returns a PAUSED server to ACTIVE status.
272
+ def unpause
273
+ post(:action, {}, {:'unpause' => nil}.to_json)
274
+ end
275
+
276
+ # Suspend a running server. Changes status to SUSPENDED.
277
+ def suspend
278
+ post(:action, {}, {:'suspend' => nil}.to_json)
279
+ end
280
+
281
+ # Resume a SUSPENDED server.
282
+ def resume
283
+ post(:action, {}, {:'resume' => nil}.to_json)
284
+ end
285
+
286
+ private
287
+
288
+ def get_security_groups
289
+ security_group_ids.map { |sg_id|
290
+ SecurityGroup.find sg_id
291
+ }
292
+ end
293
+
294
+ def get_security_group_ids(security_groups=nil)
295
+ if security_groups.nil?
296
+ if persisted?
297
+
298
+ get('os-security-groups').map { |security_group| security_group.with_indifferent_access[:id] }
299
+ else
300
+
301
+ []
302
+ end
303
+ else
304
+
305
+ security_groups.map { |security_group| security_group.id }
306
+ end
307
+ end
308
+
309
+ end
310
+
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,128 @@
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
+ module OpenStack
19
+ module Nova
20
+ module Compute
21
+
22
+ class SimpleTenantUsage < Base
23
+ self.element_name = "os-simple-tenant-usage"
24
+ self.collection_name = "os-simple-tenant-usage"
25
+
26
+ schema do
27
+ attribute :total_hours, :float
28
+ attribute :total_vcpus_usage, :float
29
+ attribute :total_memory_mb_usage, :float
30
+ attribute :total_local_gb_usage, :float
31
+ attribute :stop, :datetime
32
+ attribute :start, :datetime
33
+ end
34
+
35
+ def self.find(*arguments)
36
+ scope = arguments.slice!(0)
37
+ options = arguments.slice!(0) || {}
38
+
39
+ # Add "detailed => 1" to the query_options because of broken RESTful
40
+ # (see: http://api.openstack.org @"Simple Usage") - DG - 09/07/2012
41
+ if options[:params].nil?
42
+ options[:params] = {:detailed => 1}
43
+ else
44
+ options[:params].merge! :detailed => 1
45
+ end
46
+
47
+ # If there is no data for the given date intervals, an empty usage will be returned.
48
+ # we "filter out" these entries
49
+ case scope
50
+ when :all then
51
+ find_every(options).select { |su| su.attributes[:tenant_id].present? }
52
+ when :first then
53
+ su = find_every(options).first
54
+ su && su.attributes[:tenant_id].present? ? su : nil
55
+ when :last then
56
+ su = find_every(options).last
57
+ su && su.attributes[:tenant_id].present? ? su : nil
58
+ when :one then
59
+ su = find_one(options)
60
+ su && su.attributes[:tenant_id].present? ? su : nil
61
+ else
62
+ su = find_single(scope, options)
63
+ su && su.attributes[:tenant_id].present? ? su : nil
64
+ end
65
+ end
66
+
67
+ def server_usages
68
+ @attributes[:server_usages].present? ? @attributes[:server_usages] : []
69
+ end
70
+
71
+ def start
72
+ DateTime.parse(@attributes[:start] + ' UTC')
73
+ end
74
+
75
+ def stop
76
+ DateTime.parse(@attributes[:stop] + ' UTC')
77
+ end
78
+
79
+ def self.find_from_date(scope, from_date)
80
+ now = Time.now.utc
81
+
82
+ find(scope, :params => {
83
+ :start => from_date.utc.strftime(OpenStack::DATETIME_FORMAT),
84
+ :end => now.strftime(OpenStack::DATETIME_FORMAT)
85
+ })
86
+
87
+ end
88
+
89
+ def self.find_between_dates(scope, from_date, to_date)
90
+ find(scope, :params => {
91
+ :start => from_date.utc.strftime(OpenStack::DATETIME_FORMAT),
92
+ :end => to_date.utc.strftime(OpenStack::DATETIME_FORMAT)
93
+ })
94
+
95
+ end
96
+
97
+ end
98
+
99
+ class ServerUsage < Base
100
+
101
+ schema do
102
+ attribute :name, :string
103
+ attribute :vcpus, :integer
104
+ attribute :uptime, :integer
105
+ attribute :hours, :float
106
+ attribute :local_gb, :integer
107
+ attribute :tenant_id, :string
108
+ attribute :flavor, :string
109
+ attribute :state, :string
110
+ attribute :memory_mb, :integer
111
+ attribute :started_at, :datetime
112
+ attribute :ended_at, :datetime
113
+ end
114
+
115
+ def started_at
116
+ DateTime.parse(@attributes[:started_at] + ' UTC')
117
+ end
118
+
119
+ def ended_at
120
+ return nil if @attributes[:ended_at].blank?
121
+ DateTime.parse(@attributes[:ended_at] + ' UTC')
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,98 @@
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
+ module OpenStack
19
+ module Nova
20
+ module Compute
21
+
22
+ class VolumeAttachment < Base
23
+ self.element_name = "volumeAttachment"
24
+ self.collection_name = "os-volume_attachments"
25
+
26
+ def self.site
27
+ superclass.site + "servers/:server_id"
28
+ end
29
+
30
+ schema do
31
+ attribute :device, :string
32
+ attribute :volume_id, :string
33
+ attribute :server_id, :string
34
+ end
35
+
36
+ validates :device, :presence => true, :format => {:with => /\A[\/\\a-zA-Z0-9]+\Z/}
37
+ validates :volume, :presence => true
38
+ validates :server, :presence => true
39
+
40
+ def initialize(attributes = {}, persisted = false)
41
+ attributes = attributes.with_indifferent_access
42
+ new_attributes = {
43
+ :device => attributes[:device],
44
+ }
45
+
46
+ new_attachment = super(new_attributes, persisted)
47
+
48
+ if attributes[:volume].present?
49
+ new_attachment.volume_id = attributes[:volume].id
50
+ else
51
+ new_attachment.volume_id = attributes[:volumeId]
52
+ end
53
+
54
+ if attributes[:server].present?
55
+ new_attachment.server_id = attributes[:server].id
56
+ else
57
+ new_attachment.server_id = attributes[:serverId]
58
+ end
59
+
60
+ new_attachment.prefix_options[:server_id] = new_attachment.server_id
61
+
62
+ new_attachment
63
+ end
64
+
65
+ # Overload ActiveRecord::encode method
66
+ # Custom encoding to deal with openstack API
67
+ def encode(options={})
68
+ to_encode = {
69
+ VolumeAttachment.element_name => {
70
+ :device => device,
71
+ :volumeId => volume_id,
72
+ :serverId => server_id
73
+ }
74
+ }
75
+ to_encode.send("to_#{self.class.format.extension}", options)
76
+ end
77
+
78
+ def server
79
+ Server.find(server_id) if server_id.present?
80
+ end
81
+
82
+ def server=(server)
83
+ @attributes[:server_id] = server.id unless !persisted?
84
+ end
85
+
86
+ def volume
87
+ Volume::Volume.find(volume_id) if volume_id.present?
88
+ end
89
+
90
+ def volume=(volume)
91
+ @attributes[:volume_id] = volume.id unless !persisted?
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+ end
98
+ end