softlayer_api 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,210 @@
1
+ #
2
+ # Copyright (c) 2014 SoftLayer Technologies, Inc. All rights reserved.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+
23
+ module SoftLayer
24
+ class Ticket < SoftLayer::ModelBase
25
+
26
+ ##
27
+ # :attr_reader:
28
+ # The title is an identifying string set when the ticket is created
29
+ sl_attr :title
30
+
31
+ ##
32
+ # :attr_reader:
33
+ # The ticket system maintains a fixed set of subjects for tickets that are used to ensure tickets make it to the right folks quickly
34
+ sl_attr :subject
35
+
36
+ ##
37
+ # :attr_reader:
38
+ # The date the ticket was last updated.
39
+ sl_attr :lastEditDate
40
+
41
+ ##
42
+ # Returns true if the ticket has "unread" updates
43
+ def has_updates?
44
+ self["newUpdatesFlag"]
45
+ end
46
+
47
+ ##
48
+ # Returns true if the ticket is a server admin ticket
49
+ def server_admin_ticket?
50
+ # note that serverAdministrationFlag comes from the server as an Integer (0, or 1)
51
+ self["serverAdministrationFlag"] != 0
52
+ end
53
+
54
+ ##
55
+ # Add an update to this ticket.
56
+ #
57
+ def update(body = nil)
58
+ self.service.edit(self.softlayer_hash, body)
59
+ end
60
+
61
+ ##
62
+ # Override of service from ModelBase. Returns the SoftLayer_Ticket service
63
+ # set up to talk to the ticket with my ID.
64
+ def service
65
+ return softlayer_client["Ticket"].object_with_id(self.id)
66
+ end
67
+
68
+ ##
69
+ # Override from model base. Requests new details about the ticket
70
+ # from the server.
71
+ def softlayer_properties(object_mask = nil)
72
+ my_service = self.service
73
+
74
+ if(object_mask)
75
+ my_service = service.object_mask(object_mask)
76
+ else
77
+ my_service = service.object_mask(self.class.default_object_mask.to_sl_object_mask)
78
+ end
79
+
80
+ my_service.getObject()
81
+ end
82
+
83
+ ##
84
+ # Returns the default object mask,as a hash, that is used when
85
+ # retrieving ticket information from the SoftLayer server.
86
+ def self.default_object_mask
87
+ {
88
+ "mask" => [
89
+ 'id', # This is an internal ticket ID, not the one usually seen in the portal
90
+ 'serviceProvider',
91
+ 'serviceProviderResourceId', # This is the ticket ID usually seen in the portal
92
+ 'title',
93
+ 'subject',
94
+ {'assignedUser' => ['username', 'firstName', 'lastName'] },
95
+ 'status.id',
96
+ 'createDate',
97
+ 'lastEditDate',
98
+ 'newUpdatesFlag', # This comes in from the server as a Boolean value
99
+ 'awaitingUserResponseFlag', # This comes in from the server as a Boolean value
100
+ 'serverAdministrationFlag', # This comes in from the server as an integer :-(
101
+ ]
102
+ }
103
+ end
104
+
105
+ ##
106
+ # Queries the SoftLayer API to retrieve a list of the valid
107
+ # ticket subjects.
108
+ def self.ticket_subjects(client = nil)
109
+ @ticket_subjects ||= nil
110
+
111
+ if !@ticket_subjects
112
+ softlayer_client = client || Client.default_client
113
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
114
+
115
+ @ticket_subjects = softlayer_client['Ticket_Subject'].getAllObjects();
116
+ end
117
+
118
+ @ticket_subjects
119
+ end
120
+
121
+ ##
122
+ # Returns the set of currently open tickets
123
+ #
124
+ # Options should contain:
125
+ #
126
+ # <b>+:client+</b> - the client in which to search for the ticket
127
+ #
128
+ # If a client is not provided then the routine will search Client::default_client
129
+ # If Client::default_client is also nil the routine will raise an error.
130
+ def self.open_tickets(options = {})
131
+ softlayer_client = options[:client] || Client.default_client
132
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
133
+
134
+ if options.has_key?(:object_mask)
135
+ object_mask = options[:object_mask]
136
+ else
137
+ object_mask = default_object_mask.to_sl_object_mask
138
+ end
139
+
140
+ open_tickets_data = softlayer_client["Account"].object_mask(object_mask).getOpenTickets
141
+ open_tickets_data.collect { |ticket_data| new(softlayer_client, ticket_data) }
142
+ end
143
+
144
+ ##
145
+ # Find the ticket with the given ID and return it
146
+ #
147
+ # Options should contain:
148
+ #
149
+ # <b>+:client+</b> - the client in which to search for the ticket
150
+ #
151
+ # If a client is not provided then the routine will search Client::default_client
152
+ # If Client::default_client is also nil the routine will raise an error.
153
+ #
154
+ def self.ticket_with_id(ticket_id, options = {})
155
+ softlayer_client = options[:client] || Client.default_client
156
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
157
+
158
+ if options.has_key?(:object_mask)
159
+ object_mask = options[:object_mask]
160
+ else
161
+ object_mask = default_object_mask.to_sl_object_mask
162
+ end
163
+
164
+ ticket_data = softlayer_client["Ticket"].object_with_id(ticket_id).object_mask(object_mask).getObject()
165
+
166
+ return new(softlayer_client, ticket_data)
167
+ end
168
+
169
+ ##
170
+ # Create and submit a new support Ticket to SoftLayer.
171
+ #
172
+ # The options parameter should contain:
173
+ #
174
+ # <b>+:client+</b> - The client used to connect to the API
175
+ #
176
+ # If no client is given, then the routine will try to use Client.default_client
177
+ # If no client can be found the routine will raise an error.
178
+ #
179
+ # The options should also contain:
180
+ #
181
+ # * <b>+:title+</b> (String) - The user provided title for the ticket.
182
+ # * <b>+:body+</b> (String) - The content of the ticket
183
+ # * <b>+:subject_id+</b> (Int) - The id of a subject to use for the ticket. A list of ticket subjects can be returned by SoftLayer::Ticket.ticket_subjects
184
+ # * <b>+:assigned_user_id+</b> (Int) - The id of a user to whom the ticket should be assigned
185
+ def self.create_standard_ticket(options = {})
186
+ softlayer_client = options[:client] || SoftLayer::Client.default_client
187
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
188
+
189
+ title = options[:title]
190
+ body = options[:body]
191
+ subject_id = options[:subject_id]
192
+ assigned_user_id = options[:assigned_user_id]
193
+
194
+ if(nil == assigned_user_id)
195
+ current_user = softlayer_client["Account"].object_mask("id").getCurrentUser()
196
+ assigned_user_id = current_user["id"]
197
+ end
198
+
199
+ new_ticket = {
200
+ 'subjectId' => subject_id,
201
+ 'contents' => body,
202
+ 'assignedUserId' => assigned_user_id,
203
+ 'title' => title
204
+ }
205
+
206
+ ticket_data = softlayer_client["Ticket"].createStandardTicket(new_ticket, body)
207
+ return new(softlayer_client, ticket_data)
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,388 @@
1
+ #
2
+ # Copyright (c) 2014 SoftLayer Technologies, Inc. All rights reserved.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+
23
+ require 'time'
24
+
25
+ module SoftLayer
26
+ ##
27
+ # Instance of this class represent servers that are virtual machines in the
28
+ # SoftLayer environment.
29
+ #
30
+ # This class roughly corresponds to the entity SoftLayer_Virtual_Guest in the
31
+ # API.
32
+ #
33
+ class VirtualServer < Server
34
+ include ::SoftLayer::DynamicAttribute
35
+
36
+ ##
37
+ # :attr_reader:
38
+ # A count of the nubmer of virtual processing cores allocated
39
+ # to the server.
40
+ sl_attr :cores, 'maxCpu'
41
+
42
+ ##
43
+ # :attr_reader:
44
+ # The date the Virtual Server was provisioned. This attribute can be
45
+ # nil if the SoftLayer system has not yet finished provisioning the
46
+ # server (consequently this attribute is used by the #wait_until_ready
47
+ # method to determine when a server has been provisioned)
48
+ sl_attr :provisionDate
49
+
50
+ ##
51
+ # :attr_reader:
52
+ # The active transaction (if any) for this virtual server. Transactions
53
+ # are used to make configuration changes to the server and only one
54
+ # transaction can be active at a time.
55
+ sl_attr :activeTransaction
56
+
57
+ ##
58
+ # :attr_reader:
59
+ # Storage devices attached to the server. Storage may be local
60
+ # to the host running the Virtual Server, or it may be located
61
+ # on the SAN
62
+ sl_attr :blockDevices
63
+
64
+ ##
65
+ # :attr_reader:
66
+ # The last operating system reload transaction that was
67
+ # run for this server. #wait_until_ready compares the
68
+ # ID of this transaction to the ID of the active transaction
69
+ # to determine if an OS reload is in progress.
70
+ sl_attr :lastOperatingSystemReload
71
+
72
+ ##
73
+ # A virtual server can find out about items that are
74
+ # available for upgrades.
75
+ #
76
+ sl_dynamic_attr :upgrade_options do |resource|
77
+ resource.should_update? do
78
+ @upgrade_items == nil
79
+ end
80
+
81
+ resource.to_update do
82
+ self.service.object_mask("mask[id,categories.categoryCode,item[id,capacity,units,attributes,prices]]").getUpgradeItemPrices(true)
83
+ end
84
+ end
85
+
86
+ ##
87
+ # IMMEDIATELY cancel this virtual server
88
+ #
89
+ def cancel!
90
+ self.service.deleteObject()
91
+ end
92
+
93
+ ##
94
+ # This routine submits an order to upgrade the cpu count of the virtual server.
95
+ # The order may result in additional charges being applied to SoftLayer account
96
+ #
97
+ # This routine can also "downgrade" servers (set their cpu count lower)
98
+ #
99
+ # The routine returns true if the order is placed and false if it is not
100
+ #
101
+ def upgrade_cores!(num_cores)
102
+ upgrade_item_price = _item_price_in_category("guest_core", num_cores)
103
+ _order_upgrade_item!(upgrade_item_price) if upgrade_item_price
104
+ nil != upgrade_item_price
105
+ end
106
+
107
+ ##
108
+ # This routine submits an order to change the RAM available to the virtual server.
109
+ # Pass in the desired amount of RAM for the server in Gigabytes
110
+ #
111
+ # The order may result in additional charges being applied to SoftLayer account
112
+ #
113
+ # The routine returns true if the order is placed and false if it is not
114
+ #
115
+ def upgrade_RAM!(ram_in_GB)
116
+ upgrade_item_price = _item_price_in_category("ram", ram_in_GB)
117
+ _order_upgrade_item!(upgrade_item_price) if upgrade_item_price
118
+ nil != upgrade_item_price
119
+ end
120
+
121
+ ##
122
+ # This routine submits an order to change the maximum nic speed of the server
123
+ # Pass in the desired speed in Megabits per second (typically 10, 100, or 1000)
124
+ # (since you may choose a slower speed this routine can also be used for "downgrades")
125
+ #
126
+ # The order may result in additional charges being applied to SoftLayer account
127
+ #
128
+ # The routine returns true if the order is placed and false if it is not
129
+ #
130
+ def upgrade_max_port_speed!(network_speed_in_Mbps)
131
+ upgrade_item_price = _item_price_in_category("port_speed", network_speed_in_Mbps)
132
+ _order_upgrade_item!(upgrade_item_price) if upgrade_item_price
133
+ nil != upgrade_item_price
134
+ end
135
+
136
+ ##
137
+ # Capture a disk image of this virtual server for use with other servers.
138
+ #
139
+ # image_name will become the name of the image in the portal.
140
+ #
141
+ # If include_attached_storage is true, the images of attached storage will be
142
+ # included as well.
143
+ #
144
+ # The image_notes should be a string and will be added to the image as notes.
145
+ #
146
+ def capture_image(image_name, include_attached_storage = false, image_notes = nil)
147
+ disk_filter = lambda { |disk| disk['device'] == '0' }
148
+ disk_filter = lambda { |disk| disk['device'] == '1' } if include_attached_storage
149
+
150
+ disks = self.blockDevices.select(&disk_filter)
151
+
152
+ self.service.createArchiveTransaction(image_name, disks, notes) if disks && !disks.empty?
153
+ end
154
+
155
+ ##
156
+ # Repeatedly polls the API to find out if this server is 'ready'.
157
+ #
158
+ # The server is ready when it is provisioned and any operating system reloads have completed.
159
+ #
160
+ # If wait_for_transactions is true, then the routine will poll until all transactions
161
+ # (not just an OS Reload) have completed on the server.
162
+ #
163
+ # max_trials is the maximum number of times the routine will poll the API
164
+ # seconds_between_tries is the polling interval (in seconds)
165
+ #
166
+ # The routine returns true if the server was found to be ready. If max_trials
167
+ # is exceeded and the server is still not ready, the routine returns false
168
+ #
169
+ # If a block is passed to this routine it will be called on each trial with
170
+ # a boolean argument representing whether or not the server is ready
171
+ #
172
+ # Calling this routine will (in essence) block the thread on which the request is made.
173
+ #
174
+ def wait_until_ready(max_trials, wait_for_transactions = false, seconds_between_tries = 2)
175
+ # pessimistically assume the server is not ready
176
+ num_trials = 0
177
+ begin
178
+ self.refresh_details()
179
+
180
+ has_os_reload = has_sl_property? :lastOperatingSystemReload
181
+ has_active_transaction = has_sl_property? :activeTransaction
182
+
183
+ reloading_os = has_active_transaction && has_os_reload && (self.lastOperatingSystemReload['id'] == self.activeTransaction['id'])
184
+ provisioned = has_sl_property? :provisionDate
185
+
186
+ # a server is ready when it is provisioned, not reloading the OS
187
+ # (and if wait_for_transactions is true, when there are no active transactions).
188
+ ready = provisioned && !reloading_os && (!wait_for_transactions || !has_active_transaction)
189
+
190
+ num_trials = num_trials + 1
191
+
192
+ yield ready if block_given?
193
+
194
+ sleep(seconds_between_tries) if !ready && (num_trials <= max_trials)
195
+ end until ready || (num_trials >= max_trials)
196
+
197
+ ready
198
+ end
199
+
200
+ ##
201
+ # Retrive the virtual server with the given server ID from the API
202
+ #
203
+ # The options parameter should contain:
204
+ #
205
+ # <b>+:client+</b> - The client used to connect to the API
206
+ #
207
+ # If no client is given, then the routine will try to use Client.default_client
208
+ # If no client can be found the routine will raise an error.
209
+ #
210
+ # The options may include the following keys
211
+ # * <b>+:object_mask+</b> (string) - A object mask of properties, in addition to the default properties, that you wish to retrieve for the server
212
+ #
213
+ def self.server_with_id(server_id, options = {})
214
+ softlayer_client = options[:client] || Client.default_client
215
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
216
+
217
+ vg_service = softlayer_client["Virtual_Guest"]
218
+ vg_service = vg_service.object_mask(default_object_mask.to_sl_object_mask)
219
+
220
+ if options.has_key?(:object_mask)
221
+ vg_service = vg_service.object_mask(options[:object_mask])
222
+ end
223
+
224
+ server_data = vg_service.object_with_id(server_id).getObject()
225
+
226
+ return VirtualServer.new(softlayer_client, server_data)
227
+ end
228
+
229
+ ##
230
+ # Retrieve a list of virtual servers from the account.
231
+ #
232
+ # The options parameter should contain:
233
+ #
234
+ # <b>+:client+</b> - The client used to connect to the API
235
+ #
236
+ # If no client is given, then the routine will try to use Client.default_client
237
+ # If no client can be found the routine will raise an error.
238
+ #
239
+ # You may filter the list returned by adding options:
240
+ # * <b>+:hourly+</b> (boolean) - Include servers billed hourly in the list
241
+ # * <b>+:monthly+</b> (boolean) - Include servers billed monthly in the list
242
+ # * <b>+:tags+</b> (array) - an array of strings representing tags to search for on the instances
243
+ # * <b>+:cpus+</b> (int) - return virtual servers with the given number of (virtual) CPUs
244
+ # * <b>+:memory+</b> (int) - return servers with at least the given amount of memory (in MB. e.g. 4096 = 4GB)
245
+ # * <b>+:hostname+</b> (string) - return servers whose hostnames match the query string given (see ObjectFilter::query_to_filter_operation)
246
+ # * <b>+:domain+</b> (string) - filter servers to those whose domain matches the query string given (see ObjectFilter::query_to_filter_operation)
247
+ # * <b>+:local_disk+</b> (boolean) - include servers that do, or do not, have local disk storage
248
+ # * <b>+:datacenter+</b> (string) - find servers whose short data center name (e.g. dal05, sjc01) matches the query string given (see ObjectFilter::query_to_filter_operation)
249
+ # * <b>+:nic_speed+</b> (int) - include servers with the given nic speed (in Mbps, usually 10, 100, or 1000)
250
+ # * <b>+:public_ip+</b> (string) - return servers whose public IP address matches the query string given (see ObjectFilter::query_to_filter_operation)
251
+ # * <b>+:private_ip+</b> (string) - same as :public_ip, but for private IP addresses
252
+ #
253
+ # Additionally you may provide options related to the request itself:
254
+ # * <b>+:object_mask+</b> (string) - A object mask of properties, in addition to the default properties, that you wish to retrieve for the servers
255
+ # * <b>+:result_limit+</b> (hash with :limit, and :offset keys) - Limit the scope of results returned.
256
+ #
257
+ def self.find_servers(options_hash = {})
258
+ softlayer_client = options_hash[:client] || Client.default_client
259
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
260
+
261
+ object_filter = {}
262
+
263
+ option_to_filter_path = {
264
+ :cpus => "virtualGuests.maxCpu",
265
+ :memory => "virtualGuests.maxMemory",
266
+ :hostname => "virtualGuests.hostname",
267
+ :domain => "virtualGuests.domain",
268
+ :local_disk => "virtualGuests.localDiskFlag",
269
+ :datacenter => "virtualGuests.datacenter.name",
270
+ :nic_speed => "virtualGuests.networkComponents.maxSpeed",
271
+ :public_ip => "virtualGuests.primaryIpAddress",
272
+ :private_ip => "virtualGuests.primaryBackendIpAddress"
273
+ }
274
+
275
+ if options_hash.has_key?(:local_disk) then
276
+ options_hash[:local_disk] = options_hash[:local_disk] ? 1 : 0
277
+ end
278
+
279
+ # For each of the options in the option_to_filter_path map, if the options hash includes
280
+ # that particular option, add a clause to the object filter that filters for the matching
281
+ # value
282
+ option_to_filter_path.each do |option, filter_path|
283
+ object_filter.merge!(SoftLayer::ObjectFilter.build(filter_path, options_hash[option])) if options_hash.has_key?(option)
284
+ end
285
+
286
+ # Tags get a much more complex object filter operation so we handle them separately
287
+ if options_hash.has_key?(:tags)
288
+ object_filter.merge!(SoftLayer::ObjectFilter.build("virtualGuests.tagReferences.tag.name", {
289
+ 'operation' => 'in',
290
+ 'options' => [{
291
+ 'name' => 'data',
292
+ 'value' => options_hash[:tags]
293
+ }]
294
+ } ));
295
+ end
296
+
297
+ required_properties_mask = 'mask.id'
298
+
299
+ account_service = softlayer_client['Account']
300
+ account_service = account_service.object_filter(object_filter) unless object_filter.empty?
301
+ account_service = account_service.object_mask(default_object_mask.to_sl_object_mask)
302
+
303
+ if options_hash.has_key? :object_mask
304
+ account_service = account_service.object_mask(options_hash[:object_mask])
305
+ end
306
+
307
+ if options_hash.has_key?(:result_limit)
308
+ offset = options[:result_limit][:offset]
309
+ limit = options[:result_limit][:limit]
310
+
311
+ account_service = account_service.result_limit(offset, limit)
312
+ end
313
+
314
+ case
315
+ when options_hash[:hourly] && options_hash[:monthly]
316
+ virtual_server_data = account_service.getVirtualGuests()
317
+ when options_hash[:hourly]
318
+ virtual_server_data = account_service.getHourlyVirtualGuests()
319
+ when options_hash[:monthly]
320
+ virtual_server_data = account_service.getMonthlyVirtualGuests()
321
+ else
322
+ virtual_server_data = account_service.getVirtualGuests()
323
+ end
324
+
325
+ virtual_server_data.collect { |server_data| VirtualServer.new(softlayer_client, server_data) }
326
+ end
327
+
328
+ ##
329
+ # Returns the default object mask used when fetching servers from the API
330
+ def self.default_object_mask
331
+ sub_mask = {
332
+ "mask(SoftLayer_Virtual_Guest)" => [
333
+ 'createDate',
334
+ 'modifyDate',
335
+ 'provisionDate',
336
+ 'dedicatedAccountHostOnlyFlag',
337
+ 'lastKnownPowerState.name',
338
+ 'powerState',
339
+ 'status',
340
+ 'maxCpu',
341
+ 'maxMemory',
342
+ 'activeTransaction[id, transactionStatus[friendlyName,name]]',
343
+ 'networkComponents[id, status, speed, maxSpeed, name, macAddress, primaryIpAddress, port, primarySubnet]',
344
+ 'lastOperatingSystemReload.id',
345
+ 'blockDevices',
346
+ 'blockDeviceTemplateGroup[id, name, globalIdentifier]'
347
+ ]
348
+ }
349
+
350
+ super.merge(sub_mask)
351
+ end #default_object_mask
352
+
353
+ ##
354
+ # Returns the SoftLayer Service that represents calls to this object
355
+ # For VirtualServers the service is +SoftLayer_Virtual_Guest+ and
356
+ # addressing this object is done by id.
357
+ def service
358
+ return softlayer_client["Virtual_Guest"].object_with_id(self.id)
359
+ end
360
+
361
+ private
362
+
363
+ ##
364
+ # Searches through the upgrade items pricess known to this server for the one that is in a particular category
365
+ # and whose capacity matches the value given. Returns the item_price or nil
366
+ #
367
+ def _item_price_in_category(which_category, capacity)
368
+ item_prices_in_category = self.upgrade_items.select { |item_price| item_price["categories"].find { |category| category["categoryCode"] == which_category } }
369
+ item_prices_in_category.find { |ram_item| ram_item["item"]["capacity"].to_i == capacity}
370
+ end
371
+
372
+ ##
373
+ # Constructs an upgrade order to order the given item price.
374
+ # The order is built to execute immediately
375
+ #
376
+ def _order_upgrade_item!(upgrade_item_price)
377
+ # put together an order
378
+ upgrade_order = {
379
+ 'complexType' => 'SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade',
380
+ 'virtualGuests' => [{'id' => self.id }],
381
+ 'properties' => [{'name' => 'MAINTENANCE_WINDOW', 'value' => Time.now.iso8601}],
382
+ 'prices' => [ upgrade_item_price ]
383
+ }
384
+
385
+ self.softlayer_client["Product_Order"].placeOrder(upgrade_order)
386
+ end
387
+ end #class VirtualServer
388
+ end