openstack_activeresource 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +14 -0
- data/README.rdoc +427 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/lib/hot_fixes.rb +55 -0
- data/lib/locales/en.yml +5 -0
- data/lib/open_stack/base.rb +88 -0
- data/lib/open_stack/common.rb +56 -0
- data/lib/open_stack/glance/base.rb +39 -0
- data/lib/open_stack/glance/image.rb +33 -0
- data/lib/open_stack/glance.rb +27 -0
- data/lib/open_stack/keystone/admin/base.rb +41 -0
- data/lib/open_stack/keystone/admin/role.rb +35 -0
- data/lib/open_stack/keystone/admin/tenant.rb +104 -0
- data/lib/open_stack/keystone/admin/user.rb +98 -0
- data/lib/open_stack/keystone/admin/user_role.rb +34 -0
- data/lib/open_stack/keystone/admin.rb +32 -0
- data/lib/open_stack/keystone/public/auth.rb +141 -0
- data/lib/open_stack/keystone/public/base.rb +41 -0
- data/lib/open_stack/keystone/public/tenant.rb +64 -0
- data/lib/open_stack/keystone/public.rb +31 -0
- data/lib/open_stack/keystone.rb +27 -0
- data/lib/open_stack/nova/compute/base.rb +41 -0
- data/lib/open_stack/nova/compute/base_detail.rb +59 -0
- data/lib/open_stack/nova/compute/flavor.rb +56 -0
- data/lib/open_stack/nova/compute/floating_ip.rb +61 -0
- data/lib/open_stack/nova/compute/floating_ip_pool.rb +36 -0
- data/lib/open_stack/nova/compute/image.rb +76 -0
- data/lib/open_stack/nova/compute/key_pair.rb +47 -0
- data/lib/open_stack/nova/compute/network.rb +45 -0
- data/lib/open_stack/nova/compute/security_group.rb +117 -0
- data/lib/open_stack/nova/compute/server.rb +313 -0
- data/lib/open_stack/nova/compute/simple_tenant_usage.rb +128 -0
- data/lib/open_stack/nova/compute/volume_attachment.rb +98 -0
- data/lib/open_stack/nova/compute.rb +39 -0
- data/lib/open_stack/nova/volume/base.rb +41 -0
- data/lib/open_stack/nova/volume/volume.rb +77 -0
- data/lib/open_stack/nova/volume.rb +29 -0
- data/lib/open_stack/nova.rb +27 -0
- data/lib/open_stack.rb +40 -0
- data/lib/openstack_activeresource.rb +1 -0
- data/test/helper.rb +18 -0
- data/test/test_openstack-activeresource.rb +7 -0
- 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
|