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.
- 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
|