softlayer_api 2.0.1 → 2.1.0

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