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,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?