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,227 @@
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
+ #
25
+ # This class allows you to order a Bare Metal Server by providing
26
+ # a simple set of attributes for the newly created server. The
27
+ # SoftLayer system will select a server that matches the attributes
28
+ # provided and provision it or will report an error.
29
+ #
30
+ # If you wish to have more exacting control over the set of options
31
+ # that go into configuring the server, please see the
32
+ # BareMetalServerOrder_Package class.
33
+ #
34
+ # This class creates the server with the SoftLayer_Hardware::createObject
35
+ # method.
36
+ #
37
+ # http://sldn.softlayer.com/reference/services/SoftLayer_Hardware/createObject
38
+ #
39
+ # Reading that documentation may help you understand the options presented here.
40
+ #
41
+ class BareMetalServerOrder
42
+ #--
43
+ # Required Attributes
44
+ # -------------------
45
+ # The following attributes are required in order to successfully order
46
+ # a Bare Metal Instance
47
+ #++
48
+
49
+ # String, short name of the data center that will house the new Bare Metal Instance (e.g. "dal05" or "sea01")
50
+ # Corresponds to +datacenter.name+ in the documentation for +createObject+.
51
+ attr_accessor :datacenter
52
+
53
+ # String, The hostname to assign to the new server
54
+ attr_accessor :hostname
55
+
56
+ # String, The domain (i.e. softlayer.com) for the new server
57
+ attr_accessor :domain
58
+
59
+ # Integer, The number of cpu cores to include in the instance
60
+ # Corresponds to +processorCoreAmount+ in the documentation for +createObject+
61
+ attr_accessor :cores
62
+
63
+ # Integer, The amount of RAM for the new server (specified in Gigabytes so a value of 4 is 4GB)
64
+ # Corresponds to +memoryCapacity+ in the documentation for +createObject+
65
+ attr_accessor :memory
66
+
67
+ # String, An OS reference code for the operating system to install on the server
68
+ # Corresponds to +operatingSystemReferenceCode+ in the +createObject+ documentation
69
+ attr_accessor :os_reference_code
70
+
71
+ #--
72
+ # Optional attributes
73
+ #++
74
+
75
+ # Boolean, If true, an hourly server will be ordered, otherwise a monthly server will be ordered
76
+ # Corresponds to +hourlyBillingFlag+ in the +createObject+ documentation
77
+ attr_accessor :hourly
78
+
79
+ # Integer, The id of the public VLAN this server should join
80
+ # Corresponds to +primaryNetworkComponent.networkVlan.id+ in the +createObject+ documentation
81
+ attr_accessor :public_vlan_id
82
+
83
+ # Integer, The id of the private VLAN this server should join
84
+ # Corresponds to +primaryBackendNetworkComponent.networkVlan.id+ in the +createObject+ documentation
85
+ attr_accessor :private_vlan_id
86
+
87
+ # Array of Integer, Sizes (in gigabytes... so use 25 to get a 25GB disk) of disks to attach to this server
88
+ # This roughly Corresponds to +hardDrives+ field in the +createObject+ documentation.
89
+ attr_accessor :disks
90
+
91
+ # Array of Strings, SSH keys to add to the root user's account.
92
+ # Corresponds to +sshKeys+ in the +createObject+ documentation
93
+ attr_accessor :ssh_key_ids
94
+
95
+ # Object responding to to_s and providing a valid URI, The URI of a post provisioning script to run on
96
+ # this server once it is created.
97
+ # Corresponds to +postInstallScriptUri+ in the +createObject+ documentation
98
+ attr_accessor :provision_script_URI
99
+
100
+ # Boolean, If true then the server will only have a private network interface (and no public network interface)
101
+ # Corresponds to +privateNetworkOnlyFlag+ in the +createObject+ documentation
102
+ attr_accessor :private_network_only
103
+
104
+ # String, User metadata associated with the instance
105
+ # Corresponds to +userData.value+ in the +createObject+ documentation
106
+ attr_accessor :user_metadata
107
+
108
+ # Integer (Should be 10, 100, or 1000), The maximum network interface card speed (in Mbps) for the new instance
109
+ # Corresponds to +networkComponents.maxSpeed+ in the +createObject+ documentation
110
+ attr_accessor :max_port_speed
111
+
112
+ ##
113
+ # Create a new order that works thorugh the given client connection
114
+ def initialize (client = nil)
115
+ @softlayer_client = client || Client.default_client
116
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !@softlayer_client
117
+ end
118
+
119
+ ##
120
+ # Calls the SoftLayer API to verify that the template provided by this order is valid
121
+ # This routine will return the order template generated by the API or will throw an exception
122
+ #
123
+ # This routine will not actually create a Bare Metal Instance and will not affect billing.
124
+ #
125
+ # If you provide a block, it will receive the order template as a parameter and
126
+ # the block may make changes to the template before it is submitted.
127
+ def verify()
128
+ order_template = hardware_instance_template
129
+ order_template = yield order_template if block_given?
130
+
131
+ @softlayer_client["Hardware"].generateOrderTemplate(order_template)
132
+ end
133
+
134
+ ##
135
+ # Calls the SoftLayer API to place an order for a new server based on the template in this
136
+ # order. If this succeeds then you will be billed for the new server.
137
+ #
138
+ # If you provide a block, it will receive the order template as a parameter and
139
+ # the block may make changes to the template before it is submitted.
140
+ def place_order!()
141
+ order_template = hardware_instance_template
142
+ order_template = yield order_template if block_given?
143
+
144
+ server_hash = @softlayer_client["Hardware"].createObject(order_template)
145
+ SoftLayer::BareMetalServer.server_with_id(server_hash["id"], :client => @softlayer_client) if server_hash
146
+ end
147
+
148
+ protected
149
+
150
+ ##
151
+ # Returns a hash of the creation options formatted to be sent to
152
+ # the SoftLayer API for either verification or completion
153
+ def hardware_instance_template
154
+ template = {
155
+ "processorCoreAmount" => @cores.to_i,
156
+ "memoryCapacity" => @memory.to_i,
157
+ "hostname" => @hostname,
158
+ "domain" => @domain,
159
+ "operatingSystemReferenceCode" => @os_reference_code,
160
+
161
+ # Note : for the values below, we want to use the constants "true" and "false" not nil
162
+ # the nil value (while false to Ruby) will not translate to XML properly
163
+ "localDiskFlag" => !!@use_local_disk,
164
+ "hourlyBillingFlag" => !!@hourly
165
+ }
166
+
167
+ template["privateNetworkOnlyFlag"] = true if @private_network_only
168
+
169
+ template["datacenter"] = {"name" => @datacenter} if @datacenter
170
+ template['userData'] = [{'value' => @user_metadata}] if @user_metadata
171
+ template['networkComponents'] = [{'maxSpeed'=> @max_port_speed}] if @max_port_speed
172
+ template['postInstallScriptUri'] = @provision_script_URI.to_s if @provision_script_URI
173
+ template['sshKeys'] = @ssh_key_ids.collect { |ssh_key| {'id'=> ssh_key.to_i } } if @ssh_key_ids
174
+ template['primaryNetworkComponent'] = { "networkVlan" => { "id" => @public_vlan_id.to_i } } if @public_vlan_id
175
+ template["primaryBackendNetworkComponent"] = { "networkVlan" => {"id" => @private_vlan_id.to_i } } if @private_vlan_id
176
+
177
+ if @disks && !@disks.empty?
178
+ template['hardDrives'] = @disks.collect do |disk|
179
+ {"capacity" => disk.to_i}
180
+ end
181
+ end
182
+
183
+ template
184
+ end
185
+
186
+ ##
187
+ # The first time this is called it requests SoftLayer_Hardware::getCreateObjectOptions
188
+ # from the API and remembers the result. On subsequent calls it returns the remembered result.
189
+ def self.create_object_options(client = nil)
190
+ softlayer_client = client || Client.default_client
191
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !softlayer_client
192
+
193
+ @@create_object_options ||= nil
194
+ @@create_object_options = softlayer_client["Hardware"].getCreateObjectOptions() if !@@create_object_options
195
+ @@create_object_options
196
+ end
197
+
198
+ ##
199
+ # Return a list of values that are valid for the :datacenter attribute
200
+ def self.datacenter_options(client = nil)
201
+ create_object_options(client)["datacenters"].collect { |datacenter_spec| datacenter_spec['template']['datacenter']["name"] }.uniq.sort!
202
+ end
203
+
204
+ def self.core_options(client = nil)
205
+ create_object_options(client)["processors"].collect { |processor_spec| processor_spec['template']['processorCoreAmount'] }.uniq.sort!
206
+ end
207
+
208
+ ##
209
+ # Return a list of values that are valid the array given to the :disks
210
+ def self.disk_options(client = nil)
211
+ create_object_options(client)["hardDrives"].collect { |disk_spec| disk_spec['template']['hardDrives'][0]['capacity'].to_i}.uniq.sort!
212
+ end
213
+
214
+ ##
215
+ # Returns a list of the valid :os_refrence_codes
216
+ def self.os_reference_code_options(client = nil)
217
+ create_object_options(client)["operatingSystems"].collect { |os_spec| os_spec['template']['operatingSystemReferenceCode'] }.uniq.sort!
218
+ end
219
+
220
+ ##
221
+ # Returns a list of the :max_port_speeds
222
+ def self.max_port_speed_options(client = nil)
223
+ create_object_options(client)["networkComponents"].collect { |component_spec| component_spec['template']['networkComponents'][0]['maxSpeed'] }
224
+ end
225
+
226
+ end # class BareMetalServerOrder
227
+ end # module SoftLayer
@@ -0,0 +1,162 @@
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
+ #
25
+ # This class is used to order a hardware server using a product package.
26
+ #
27
+ # Ordering a server using a product package is a more complex process than
28
+ # ordering with simple attributes (as is done by the BareMetalServerOrder class).
29
+ # However with that complexity comes the the ability to specify the configuration
30
+ # of the server in exacting detail.
31
+ #
32
+ # To use this class, you first select a product package. The product package
33
+ # defines the base configuration, the chassis, of the server as well as the set of configuration
34
+ # options available for that chassis. To fully configure the server you must select
35
+ # the value for each configuration option.
36
+ #
37
+ # This class roughly Corresponds to the SoftLayer_Container_Product_Order_Hardware_Server
38
+ # data type in the SoftLayer API
39
+ #
40
+ # http://sldn.softlayer.com/reference/datatypes/SoftLayer_Container_Product_Order_Hardware_Server
41
+ #
42
+ class BareMetalServerOrder_Package < Server
43
+ # The following properties are required in a server order.
44
+
45
+ # The product package identifying the base configuration for the server.
46
+ # a list of Bare Metal Server product packages is returned by
47
+ # SoftLayer::ProductPackage.bare_metal_server_packages
48
+ attr_reader :package
49
+
50
+ # String, short name of the data center that will house the new virtual server (e.g. "dal05" or "sea01")
51
+ # A list of valid data centers can be found in ProductPackage#datacenter_options
52
+ attr_accessor :datacenter
53
+
54
+ # The hostname of the server being created (i.e. 'sldn' is the hostname of sldn.softlayer.com).
55
+ attr_accessor :hostname
56
+
57
+ # The domain of the server being created (i.e. 'softlayer.com' is the domain of sldn.softlayer.com)
58
+ attr_accessor :domain
59
+
60
+ # The value of this property should be a hash. The keys of the hash are ProdcutItemCategory
61
+ # codes (like 'os' and 'ram') while the values may be Integers or Objects. The Integer values
62
+ # should be the +id+ of a +SoftLayer_Product_Item_Price+ representing the configuration option
63
+ # chosen for that category. Objects must respond to the +price_id+ message and return an integer
64
+ # that is the +id+ of a +SoftLayer_Product_Item_Price+. Instances of the ProductConfigurationOption
65
+ # class behave this way.
66
+ #
67
+ # At a minimum, the configuation_options should include entries for each of the categories
68
+ # required by the package (i.e. those returned from ProductPackage#required_categories)
69
+ attr_accessor :configuration_options
70
+
71
+ # The following properties are optional, but allow further fine tuning of
72
+ # the server
73
+
74
+ # An array of the ids of SSH keys to install on the server upon provisioning
75
+ # To obtain a list of existing SSH keys, call getSshKeys on the SoftLayer_Account service:
76
+ # client['Account'].getSshKeys()
77
+ attr_accessor :ssh_key_ids
78
+
79
+ # The URI of a script to execute on the server after it has been provisioned. This may be
80
+ # any object which accepts the to_s message. The resulting string will be passed to SoftLayer API.
81
+ attr_accessor :provision_script_URI
82
+
83
+ ##
84
+ # You initialize a BareMetalServerOrder_Package by passing in the package that you
85
+ # are ordering from.
86
+ def initialize(package, client = nil)
87
+ @softlayer_client = client || Client.default_client
88
+ raise "#{__method__} requires a client but none was given and Client::default_client is not set" if !@softlayer_client
89
+
90
+ @package = package
91
+ @configuration_options = []
92
+ end
93
+
94
+ ##
95
+ # Present the order for verification by the SoftLayer ordering system.
96
+ # The order is verified, but not executed. This should not
97
+ # change the billing of your account.
98
+ #
99
+ # If you add a block to the method call, it will receive the product
100
+ # order template before it is sent to the API. You may **carefully** make
101
+ # changes to the template to provide specialized configuration.
102
+ #
103
+ def verify
104
+ product_order = hardware_order
105
+ product_order = yield product_order if block_given?
106
+ softlayer_client["Product_Order"].verifyOrder(product_order)
107
+ end
108
+
109
+ ##
110
+ # Submit the order to be executed by the SoftLayer ordering system.
111
+ # If successful this will probably result in additional billing items
112
+ # applied to your account!
113
+ #
114
+ # If you add a block to the method call, it will receive the product
115
+ # order template before it is sent to the API. You may **carefully** make
116
+ # changes to the template to provide specialized configuration.
117
+ #
118
+ # The return value of this call is a product order receipt. After
119
+ # submitting the order, it will proceed to Sales for authorization.
120
+ #
121
+ def place_order!
122
+ product_order = hardware_order
123
+ product_order = yield product_order if block_given?
124
+ softlayer_client["Product_Order"].placeOrder(product_order)
125
+ end
126
+
127
+ protected
128
+
129
+ ##
130
+ # Construct and return a hash representing a +SoftLayer_Container_Product_Order_Hardware_Server+
131
+ # based on the configuration options given.
132
+ def hardware_order
133
+ product_order = {
134
+ 'packageId' => @package.id,
135
+ 'useHourlyPricing' => false,
136
+ 'hardware' => {
137
+ 'hostname' => @hostname,
138
+ 'domain' => @domain
139
+ }
140
+ }
141
+
142
+ product_order['location'] = @package.location_id_for_datacenter_name(@datacenter.downcase) if @datacenter
143
+
144
+ product_order['sshKeys'] = [{ 'sshKeyIds' => @ssh_key_ids }] if @ssh_key_ids
145
+ product_order['provisionScripts'] = [@provision_script_URI.to_s] if @provision_script_URI
146
+
147
+ product_order['prices'] = @configuration_options.collect do |key, value|
148
+ if value.respond_to?(:price_id)
149
+ price_id = value.price_id
150
+ else
151
+ price_id = value.to_i
152
+ end
153
+
154
+ { 'id' => price_id }
155
+ end
156
+
157
+ product_order
158
+ end
159
+
160
+ end # BareMetalServerOrder_Package
161
+
162
+ end # SoftLayer
@@ -1,18 +1,40 @@
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
+
1
23
  module SoftLayer
2
24
  # Initialize an instance of the Client class. You pass in the service name
3
25
  # and optionally hash arguments specifying how the client should access the
4
26
  # SoftLayer API.
5
27
  #
6
28
  # The following symbols can be used as hash arguments to pass options to the constructor:
7
- # - <tt>:username</tt> - a non-empty string providing the username to use for requests to the service
8
- # - <tt>:api_key</tt> - a non-empty string providing the api key to use for requests to the service
9
- # - <tt>:endpoint_url</tt> - a non-empty string providing the endpoint URL to use for requests to the service
29
+ # - +:username+ - a non-empty string providing the username to use for requests to the client
30
+ # - +:api_key+ - a non-empty string providing the api key to use for requests to the client
31
+ # - +:endpoint_url+ - a non-empty string providing the endpoint URL to use for requests to the client
10
32
  #
11
33
  # If any of the options above are missing then the constructor will try to use the corresponding
12
34
  # global variable declared in the SoftLayer Module:
13
- # - <tt>$SL_API_USERNAME</tt>
14
- # - <tt>$SL_API_KEY</tt>
15
- # - <tt>$SL_API_BASE_URL</tt>
35
+ # - +$SL_API_USERNAME+
36
+ # - +$SL_API_KEY+
37
+ # - +$SL_API_BASE_URL+
16
38
  #
17
39
  class Client
18
40
  # A username passed as authentication for each request. Cannot be emtpy or nil.
@@ -27,6 +49,30 @@ module SoftLayer
27
49
  # A string passsed as the value for the User-Agent header when requests are sent to SoftLayer API.
28
50
  attr_accessor :user_agent
29
51
 
52
+ ##
53
+ # The client class maintains an (optional) default client. The default client
54
+ # will be used by many methods if you do not provide an explicit client.
55
+ @@default_client = nil
56
+
57
+ def self.default_client
58
+ return @@default_client
59
+ end
60
+
61
+ def self.default_client=(new_default)
62
+ @@default_client = new_default
63
+ end
64
+
65
+ ##
66
+ #
67
+ # Clients are built with a number of settings:
68
+ # * <b>+:username+</b> - The username of the account you wish to access through the API
69
+ # * <b>+:api_key+</b> - The API key used to authenticate the user with the API
70
+ # * <b>+:enpoint_url+</b> - The API endpoint the client should connect to. This defaults to API_PUBLIC_ENDPOINT
71
+ # * <b>+:user_agent+</b> - A string that is passed along as the user agent when the client sends requests to the server
72
+ #
73
+ # If these arguments are not provided then the client will try to locate them using other
74
+ # sources including global variables, and the SoftLayer config file (if one exists)
75
+ #
30
76
  def initialize(options = {})
31
77
  @services = { }
32
78
 
@@ -64,12 +110,11 @@ module SoftLayer
64
110
  # will be returned each time it is called for by name. Otherwise the system
65
111
  # will try to construct a new service object and return that.
66
112
  #
67
- #
68
113
  # If the service has to be created then the service_options will be passed
69
- # along to the creative function. However, when returning a previously created
114
+ # along to the creative function. However, when returning a previously created
70
115
  # Service, the service_options will be ignored.
71
116
  #
72
- # If the service_name provided does not start with 'SoftLayer__' that prefix
117
+ # If the service_name provided does not start with 'SoftLayer_' that prefix
73
118
  # will be added
74
119
  def service_named(service_name, service_options = {})
75
120
  raise ArgumentError,"Please provide a service name" if service_name.nil? || service_name.empty?