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.
- checksums.yaml +4 -4
- data/CHANGELOG.textile +36 -0
- data/README.textile +17 -7
- data/examples/account_info.rb +6 -3
- data/examples/account_servers.rb +48 -0
- data/examples/create_ticket.rb +33 -22
- data/examples/open_tickets.rb +14 -19
- data/examples/order_bare_metal_package.rb +154 -0
- data/examples/order_virtual_server.rb +85 -0
- data/examples/ticket_info.rb +13 -14
- data/lib/softlayer/APIParameterFilter.rb +100 -23
- data/lib/softlayer/Account.rb +140 -0
- data/lib/softlayer/BareMetalServer.rb +233 -0
- data/lib/softlayer/BareMetalServerOrder.rb +227 -0
- data/lib/softlayer/BareMetalServerOrder_Package.rb +162 -0
- data/lib/softlayer/Client.rb +54 -9
- data/lib/softlayer/Config.rb +2 -3
- data/lib/softlayer/DynamicAttribute.rb +170 -0
- data/lib/softlayer/ModelBase.rb +141 -0
- data/lib/softlayer/ObjectFilter.rb +61 -21
- data/lib/softlayer/ObjectMaskParser.rb +157 -0
- data/lib/softlayer/ObjectMaskProperty.rb +83 -0
- data/lib/softlayer/ObjectMaskToken.rb +107 -0
- data/lib/softlayer/ObjectMaskTokenizer.rb +88 -0
- data/lib/softlayer/ProductItemCategory.rb +137 -0
- data/lib/softlayer/ProductPackage.rb +196 -0
- data/lib/softlayer/Server.rb +245 -0
- data/lib/softlayer/Service.rb +12 -9
- data/lib/softlayer/Ticket.rb +210 -0
- data/lib/softlayer/VirtualServer.rb +388 -0
- data/lib/softlayer/VirtualServerOrder.rb +263 -0
- data/lib/softlayer/base.rb +9 -9
- data/lib/softlayer/object_mask_helpers.rb +46 -18
- data/lib/softlayer_api.rb +15 -0
- metadata +49 -15
@@ -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
|