vagrant-softlayer 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +1,38 @@
1
- require "log4r"
2
-
3
- module VagrantPlugins
4
- module SoftLayer
5
- module Action
6
- # Waits until the new machine has been rebuilt.
7
- class WaitForRebuild
8
- include Util::Warden
9
-
10
- def initialize(app, env)
11
- @app = app
12
- @logger = Log4r::Logger.new("vagrant_softlayer::action::wait_for_rebuild")
13
- end
14
-
15
- def call(env)
16
- env[:ui].info I18n.t("vagrant_softlayer.vm.wait_for_rebuild")
17
-
18
- # Defaults to 20 minutes timeout
19
- Timeout::timeout(env[:machine].provider_config.rebuild_timeout, Errors::SLRebuildTimeoutError) do
20
- @logger.debug("Checking if the instance has been rebuilt.")
21
- sl_warden do
22
- while env[:sl_machine].object_mask("activeTransactionCount").getObject["activeTransactionCount"] > 0
23
- @logger.debug("The machine is still being rebuilt. Retrying in 10 seconds.")
24
- sleep 10
25
- end
26
- end
27
- end
28
-
29
- env[:ui].info I18n.t("vagrant_softlayer.vm.rebuilt")
30
-
31
- @app.call(env)
32
- end
33
- end
34
- end
35
- end
36
- end
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module SoftLayer
5
+ module Action
6
+ # Waits until the new machine has been rebuilt.
7
+ class WaitForRebuild
8
+ include Util::Warden
9
+
10
+ def initialize(app, env)
11
+ @app = app
12
+ @logger = Log4r::Logger.new("vagrant_softlayer::action::wait_for_rebuild")
13
+ end
14
+
15
+ def call(env)
16
+ env[:ui].info I18n.t("vagrant_softlayer.vm.wait_for_rebuild")
17
+
18
+ #Rechecks every 10 sec
19
+ virtual_server = ::SoftLayer::VirtualServer.server_with_id(env[:machine].id.to_i, :client => env[:sl_client])
20
+
21
+ ready = virtual_server.wait_until_ready((env[:machine].provider_config.rebuild_timeout.to_f/10).ceil, env[:machine].provider_config.transaction_wait, 10) do |server_ready|
22
+ unless server_ready
23
+ rebuild_status = env[:sl_machine].getActiveTransaction
24
+ rebuild_status = " Rebuild status: #{rebuild_status["transactionStatus"]["friendlyName"]} (#{rebuild_status["transactionStatus"]["name"]})." if rebuild_status && ! rebuild_status.empty?
25
+ @logger.info("#{env[:machine].provider_config.hostname} is still rebuilding. Retrying in 10 seconds.#{rebuild_status}")
26
+ end
27
+ end
28
+
29
+ raise Errors::SLRebuildTimeoutError unless ready
30
+
31
+ env[:ui].info I18n.t("vagrant_softlayer.vm.rebuilt")
32
+
33
+ @app.call(env)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,268 +1,282 @@
1
- require "ostruct"
2
-
3
- module VagrantPlugins
4
- module SoftLayer
5
- class Config < Vagrant.plugin("2", :config)
6
- # The API key to access SoftLayer.
7
- attr_accessor :api_key
8
-
9
- # The endpoint SoftLayer API url.
10
- attr_accessor :endpoint_url
11
-
12
- # The username to access SoftLayer.
13
- attr_accessor :username
14
-
15
- # The datacenter shortname.
16
- attr_accessor :datacenter
17
-
18
- # Whether to allocate a dedicated instance.
19
- attr_accessor :dedicated
20
-
21
- # The disk image capacity
22
- attr_accessor :disk_capacity
23
-
24
- # The domain of the instance.
25
- attr_accessor :domain
26
-
27
- # Force the use of the private IP for all communication even if a public IP is available
28
- attr_accessor :force_private_ip
29
-
30
- # The hostname of the instance.
31
- attr_accessor :hostname
32
-
33
- # The billing type of the instance (true for hourly, false for monthly).
34
- attr_accessor :hourly_billing
35
-
36
- # The global identifier of the compute or flex image to use.
37
- attr_accessor :image_guid
38
-
39
- # The disk type of the instance (true for local, false for SAN).
40
- attr_accessor :local_disk
41
-
42
- # The amount of RAM of the instance.
43
- attr_accessor :max_memory
44
-
45
- # Network port speed in Mbps.
46
- attr_accessor :network_speed
47
-
48
- # The instance operating system identifier.
49
- attr_accessor :operating_system
50
-
51
- # URI of post-install script to download.
52
- attr_accessor :post_install
53
-
54
- # Whether or not the instance only has access to the private network.
55
- attr_accessor :private_only
56
-
57
- # The amount of time in seconds to wait for provision to complete.
58
- attr_accessor :provision_timeout
59
-
60
- # The amount of time in seconds to wait for rebuild to complete.
61
- attr_accessor :rebuild_timeout
62
-
63
- # The id or name of the ssh key to be provisioned.
64
- attr_accessor :ssh_key
65
-
66
- # The number of processors of the instance.
67
- attr_accessor :start_cpus
68
-
69
- # User defined metadata string.
70
- attr_accessor :user_data
71
-
72
- # The ID, name or qualified name of the private VLAN.
73
- attr_accessor :vlan_private
74
-
75
- # The ID, name or qualified name of the public VLAN.
76
- attr_accessor :vlan_public
77
-
78
- # The load balancers service groups to join.
79
- attr_reader :load_balancers
80
-
81
- # Automatically update DNS on create and destroy.
82
- attr_accessor :manage_dns
83
-
84
- def initialize
85
- @api_key = UNSET_VALUE
86
- @endpoint_url = UNSET_VALUE
87
- @username = UNSET_VALUE
88
-
89
- @datacenter = UNSET_VALUE
90
- @dedicated = UNSET_VALUE
91
- @disk_capacity = UNSET_VALUE
92
- @domain = UNSET_VALUE
93
- @force_private_ip = UNSET_VALUE
94
- @hostname = UNSET_VALUE
95
- @image_guid = UNSET_VALUE
96
- @hourly_billing = UNSET_VALUE
97
- @local_disk = UNSET_VALUE
98
- @max_memory = UNSET_VALUE
99
- @network_speed = UNSET_VALUE
100
- @operating_system = UNSET_VALUE
101
- @post_install = UNSET_VALUE
102
- @private_only = UNSET_VALUE
103
- @provision_timeout = UNSET_VALUE
104
- @rebuild_timeout = UNSET_VALUE
105
- @ssh_key = UNSET_VALUE
106
- @start_cpus = UNSET_VALUE
107
- @user_data = UNSET_VALUE
108
- @vlan_private = UNSET_VALUE
109
- @vlan_public = UNSET_VALUE
110
-
111
- @load_balancers = []
112
- @manage_dns = UNSET_VALUE
113
- end
114
-
115
- # Set the load balancer service group to join.
116
- #
117
- # Available options:
118
- #
119
- # :method => Routing method. Default to round robin.
120
- # :port => Load balancer virtual port.
121
- # :type => Routing type. Default to TCP.
122
- # :vip => Load balancer virtual IP address.
123
- #
124
- # An optional block will accept parameters for the
125
- # balanced service. Available parameters:
126
- #
127
- # :destination_port => TCP port on the node.
128
- # :health_check => Service health check. Default to ping.
129
- # :weight => Service weight. Default to 1.
130
- #
131
- def join_load_balancer(opts = {}, &block)
132
- # Defaults
133
- opts[:method] ||= "ROUND ROBIN"
134
- opts[:type] ||= "TCP"
135
- opts[:service] = OpenStruct.new(:destination_port => nil, :health_check => "PING", :weight => 1)
136
-
137
- yield opts[:service] if block_given?
138
-
139
- # Convert all options that belongs to
140
- # an enumeration in uppercase.
141
- opts[:method].upcase!
142
- opts[:type].upcase!
143
- opts[:service].health_check.upcase!
144
-
145
- @load_balancers << opts
146
- end
147
-
148
- def finalize!
149
- # Try to get username and api key from environment variables.
150
- # They will default to nil if the environment variables are not present.
151
- @api_key = ENV["SL_API_KEY"] if @api_key == UNSET_VALUE
152
- @username = ENV["SL_USERNAME"] if @username == UNSET_VALUE
153
-
154
- # Endpoint url defaults to public SoftLayer API url.
155
- @endpoint_url = API_PUBLIC_ENDPOINT if @endpoint_url == UNSET_VALUE
156
-
157
- # No default datacenter.
158
- @datacenter = nil if @datacenter == UNSET_VALUE
159
-
160
- # Shared instance by default.
161
- @dedicated = false if @dedicated == UNSET_VALUE
162
-
163
- # 25GB disk capacity image by default.
164
- @disk_capacity = nil if @disk_capacity == UNSET_VALUE
165
-
166
- # Domain should be specified in Vagrantfile, so we set default to nil.
167
- @domain = nil if @domain == UNSET_VALUE
168
-
169
- # Disable the use of force private IP so the default selection can take effect
170
- @force_private_ip = false if @force_private_ip == UNSET_VALUE
171
-
172
- # Hostname should be specified in Vagrantfile, either using `config.vm.hostname`
173
- # or the provider specific configuration entry.
174
- @hostname = nil if @hostname == UNSET_VALUE
175
-
176
- # Bill hourly by default.
177
- @hourly_billing = true if @hourly_billing == UNSET_VALUE
178
-
179
- # Disable the use of a specific block device image so we can leave the OS template as default
180
- @image_guid = nil if @image_guid == UNSET_VALUE
181
-
182
- # Use local disk by default.
183
- @local_disk = true if @local_disk == UNSET_VALUE
184
-
185
- # 1Gb of RAM by default.
186
- @max_memory = 1024 if @max_memory == UNSET_VALUE
187
-
188
- # 10Mbps by default.
189
- @network_speed = 10 if @network_speed == UNSET_VALUE
190
-
191
- # Provision with the latest Ubuntu by default.
192
- @operating_system = "UBUNTU_LATEST" if @operating_system == UNSET_VALUE
193
-
194
- # No post install script by default.
195
- @post_install = nil if @post_install == UNSET_VALUE
196
-
197
- # Private-network only is false by default.
198
- @private_only = false if @private_only == UNSET_VALUE
199
-
200
- # The amount of time in seconds to wait for provision to complete.
201
- @provision_timeout = 1200 if @provision_timeout == UNSET_VALUE
202
-
203
- # The amount of time in seconds to wait for rebuild to complete.
204
- @rebuild_timeout = 1200 if @rebuild_timeout == UNSET_VALUE
205
-
206
- # SSH key should be specified in Vagrantfile, so we set default to nil.
207
- @ssh_key = nil if @ssh_key == UNSET_VALUE
208
-
209
- # One processor by default.
210
- @start_cpus = 1 if @start_cpus == UNSET_VALUE
211
-
212
- # No user metadata by default.
213
- @user_data = nil if @user_data == UNSET_VALUE
214
-
215
- # No specific private VLAN by default.
216
- @vlan_private = nil if @vlan_private == UNSET_VALUE
217
-
218
- # No specific public VLAN by default.
219
- @vlan_public = nil if @vlan_public == UNSET_VALUE
220
-
221
- # DNS management off by default
222
- @manage_dns = false if @manage_dns == UNSET_VALUE
223
- end
224
-
225
- # Aliases for ssh_key for beautiful semantic.
226
- def ssh_keys=(value)
227
- @ssh_key = value
228
- end
229
-
230
- alias_method :ssh_key_id=, :ssh_keys=
231
- alias_method :ssh_key_ids=, :ssh_keys=
232
- alias_method :ssh_key_name=, :ssh_keys=
233
- alias_method :ssh_key_names=, :ssh_keys=
234
-
235
- def validate(machine)
236
- errors = []
237
-
238
- errors << I18n.t("vagrant_softlayer.config.api_key_required") if !@api_key
239
- errors << I18n.t("vagrant_softlayer.config.username_required") if !@username
240
-
241
- errors << I18n.t("vagrant_softlayer.config.domain_required") if !@domain
242
- errors << I18n.t("vagrant_softlayer.config.ssh_key_required") if !@ssh_key
243
-
244
- errors << I18n.t("vagrant_softlayer.config.img_guid_os_code_mutually_exclusive") if @image_guid && @operating_system
245
- errors << I18n.t("vagrant_softlayer.config.img_guid_capacity_mutually_exclusive") if @image_guid && @disk_capacity
246
-
247
- # Fail if both `vm.hostname` and `provider.hostname` are nil.
248
- if !@hostname && !machine.config.vm.hostname
249
- errors << I18n.t("vagrant_softlayer.config.hostname_required")
250
- end
251
-
252
- # Fail if a load balancer has been specified without vip, port or destination port.
253
- unless @load_balancers.empty?
254
- @load_balancers.each do |lb|
255
- errors << I18n.t("vagrant_softlayer.config.lb_port_vip_required") unless (lb[:vip] && lb[:port] && lb[:service].destination_port)
256
- end
257
- end
258
-
259
- # Fail if two or more load balancers has been specified with same vip and port.
260
- if @load_balancers.map { |lb| { :port => lb[:port], :vip => lb[:vip] } }.uniq!
261
- errors << I18n.t("vagrant_softlayer.config.lb_duplicate")
262
- end
263
-
264
- { "SoftLayer" => errors }
265
- end
266
- end
267
- end
268
- end
1
+ require "ostruct"
2
+
3
+ module VagrantPlugins
4
+ module SoftLayer
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # The API key to access SoftLayer.
7
+ attr_accessor :api_key
8
+
9
+ # Th SoftLayer API request timeout value in seconds
10
+ attr_accessor :api_timeout
11
+
12
+ # The endpoint SoftLayer API url.
13
+ attr_accessor :endpoint_url
14
+
15
+ # The username to access SoftLayer.
16
+ attr_accessor :username
17
+
18
+ # The datacenter shortname.
19
+ attr_accessor :datacenter
20
+
21
+ # Whether to allocate a dedicated instance.
22
+ attr_accessor :dedicated
23
+
24
+ # The disk image capacity
25
+ attr_accessor :disk_capacity
26
+
27
+ # The domain of the instance.
28
+ attr_accessor :domain
29
+
30
+ # Force the use of the private IP for all communication even if a public IP is available
31
+ attr_accessor :force_private_ip
32
+
33
+ # The hostname of the instance.
34
+ attr_accessor :hostname
35
+
36
+ # The billing type of the instance (true for hourly, false for monthly).
37
+ attr_accessor :hourly_billing
38
+
39
+ # The global identifier of the compute or flex image to use.
40
+ attr_accessor :image_guid
41
+
42
+ # The disk type of the instance (true for local, false for SAN).
43
+ attr_accessor :local_disk
44
+
45
+ # The amount of RAM of the instance.
46
+ attr_accessor :max_memory
47
+
48
+ # Network port speed in Mbps.
49
+ attr_accessor :network_speed
50
+
51
+ # The instance operating system identifier.
52
+ attr_accessor :operating_system
53
+
54
+ # URI of post-install script to download.
55
+ attr_accessor :post_install
56
+
57
+ # Whether or not the instance only has access to the private network.
58
+ attr_accessor :private_only
59
+
60
+ # The amount of time in seconds to wait for provision to complete.
61
+ attr_accessor :provision_timeout
62
+
63
+ # The amount of time in seconds to wait for rebuild to complete.
64
+ attr_accessor :rebuild_timeout
65
+
66
+ # The id or name of the ssh key to be provisioned.
67
+ attr_accessor :ssh_key
68
+
69
+ # The number of processors of the instance.
70
+ attr_accessor :start_cpus
71
+
72
+ # Whether to wait for transaction completion on actions that place orders
73
+ attr_accessor :transaction_wait
74
+
75
+ # User defined metadata string.
76
+ attr_accessor :user_data
77
+
78
+ # The ID, name or qualified name of the private VLAN.
79
+ attr_accessor :vlan_private
80
+
81
+ # The ID, name or qualified name of the public VLAN.
82
+ attr_accessor :vlan_public
83
+
84
+ # The load balancers service groups to join.
85
+ attr_reader :load_balancers
86
+
87
+ # Automatically update DNS on create and destroy.
88
+ attr_accessor :manage_dns
89
+
90
+ def initialize
91
+ @api_key = UNSET_VALUE
92
+ @api_timeout = UNSET_VALUE
93
+ @endpoint_url = UNSET_VALUE
94
+ @username = UNSET_VALUE
95
+
96
+ @datacenter = UNSET_VALUE
97
+ @dedicated = UNSET_VALUE
98
+ @disk_capacity = UNSET_VALUE
99
+ @domain = UNSET_VALUE
100
+ @force_private_ip = UNSET_VALUE
101
+ @hostname = UNSET_VALUE
102
+ @image_guid = UNSET_VALUE
103
+ @hourly_billing = UNSET_VALUE
104
+ @local_disk = UNSET_VALUE
105
+ @max_memory = UNSET_VALUE
106
+ @network_speed = UNSET_VALUE
107
+ @operating_system = UNSET_VALUE
108
+ @post_install = UNSET_VALUE
109
+ @private_only = UNSET_VALUE
110
+ @provision_timeout = UNSET_VALUE
111
+ @rebuild_timeout = UNSET_VALUE
112
+ @ssh_key = UNSET_VALUE
113
+ @start_cpus = UNSET_VALUE
114
+ @transaction_wait = UNSET_VALUE
115
+ @user_data = UNSET_VALUE
116
+ @vlan_private = UNSET_VALUE
117
+ @vlan_public = UNSET_VALUE
118
+
119
+ @load_balancers = []
120
+ @manage_dns = UNSET_VALUE
121
+ end
122
+
123
+ # Set the load balancer service group to join.
124
+ #
125
+ # Available options:
126
+ #
127
+ # :method => Routing method. Default to round robin.
128
+ # :port => Load balancer virtual port.
129
+ # :type => Routing type. Default to TCP.
130
+ # :vip => Load balancer virtual IP address.
131
+ #
132
+ # An optional block will accept parameters for the
133
+ # balanced service. Available parameters:
134
+ #
135
+ # :destination_port => TCP port on the node.
136
+ # :health_check => Service health check. Default to ping.
137
+ # :weight => Service weight. Default to 1.
138
+ #
139
+ def join_load_balancer(opts = {}, &block)
140
+ # Defaults
141
+ opts[:method] ||= "ROUND ROBIN"
142
+ opts[:type] ||= "TCP"
143
+ opts[:service] = OpenStruct.new(:destination_port => nil, :health_check => "PING", :weight => 1)
144
+
145
+ yield opts[:service] if block_given?
146
+
147
+ # Convert all options that belongs to
148
+ # an enumeration in uppercase.
149
+ opts[:method].upcase!
150
+ opts[:type].upcase!
151
+ opts[:service].health_check.upcase!
152
+
153
+ @load_balancers << opts
154
+ end
155
+
156
+ def finalize!
157
+ # Try to get username and api key from environment variables.
158
+ # They will default to nil if the environment variables are not present.
159
+ @api_key = ENV["SL_API_KEY"] if @api_key == UNSET_VALUE
160
+ @username = ENV["SL_USERNAME"] if @username == UNSET_VALUE
161
+
162
+ # Th SoftLayer API request timeout value in seconds
163
+ @api_timeout = 60 if @api_timeout == UNSET_VALUE
164
+
165
+ # Endpoint url defaults to public SoftLayer API url.
166
+ @endpoint_url = API_PUBLIC_ENDPOINT if @endpoint_url == UNSET_VALUE
167
+
168
+ # No default datacenter.
169
+ @datacenter = nil if @datacenter == UNSET_VALUE
170
+
171
+ # Shared instance by default.
172
+ @dedicated = false if @dedicated == UNSET_VALUE
173
+
174
+ # 25GB disk capacity image by default.
175
+ @disk_capacity = nil if @disk_capacity == UNSET_VALUE
176
+
177
+ # Domain should be specified in Vagrantfile, so we set default to nil.
178
+ @domain = nil if @domain == UNSET_VALUE
179
+
180
+ # Disable the use of force private IP so the default selection can take effect
181
+ @force_private_ip = false if @force_private_ip == UNSET_VALUE
182
+
183
+ # Hostname should be specified in Vagrantfile, either using `config.vm.hostname`
184
+ # or the provider specific configuration entry.
185
+ @hostname = nil if @hostname == UNSET_VALUE
186
+
187
+ # Bill hourly by default.
188
+ @hourly_billing = true if @hourly_billing == UNSET_VALUE
189
+
190
+ # Disable the use of a specific block device image so we can leave the OS template as default
191
+ @image_guid = nil if @image_guid == UNSET_VALUE
192
+
193
+ # Use local disk by default.
194
+ @local_disk = true if @local_disk == UNSET_VALUE
195
+
196
+ # 1Gb of RAM by default.
197
+ @max_memory = 1024 if @max_memory == UNSET_VALUE
198
+
199
+ # 10Mbps by default.
200
+ @network_speed = 10 if @network_speed == UNSET_VALUE
201
+
202
+ # Provision with the latest Ubuntu by default.
203
+ @operating_system = "UBUNTU_LATEST" if @operating_system == UNSET_VALUE
204
+
205
+ # No post install script by default.
206
+ @post_install = nil if @post_install == UNSET_VALUE
207
+
208
+ # Private-network only is false by default.
209
+ @private_only = false if @private_only == UNSET_VALUE
210
+
211
+ # The amount of time in seconds to wait for provision to complete.
212
+ @provision_timeout = 1200 if @provision_timeout == UNSET_VALUE
213
+
214
+ # The amount of time in seconds to wait for rebuild to complete.
215
+ @rebuild_timeout = 1200 if @rebuild_timeout == UNSET_VALUE
216
+
217
+ # SSH key should be specified in Vagrantfile, so we set default to nil.
218
+ @ssh_key = nil if @ssh_key == UNSET_VALUE
219
+
220
+ # One processor by default.
221
+ @start_cpus = 1 if @start_cpus == UNSET_VALUE
222
+
223
+ # Whether to wait for transaction completion on actions that place orders
224
+ @transaction_wait = true if @start_cpus == UNSET_VALUE
225
+
226
+ # No user metadata by default.
227
+ @user_data = nil if @user_data == UNSET_VALUE
228
+
229
+ # No specific private VLAN by default.
230
+ @vlan_private = nil if @vlan_private == UNSET_VALUE
231
+
232
+ # No specific public VLAN by default.
233
+ @vlan_public = nil if @vlan_public == UNSET_VALUE
234
+
235
+ # DNS management off by default
236
+ @manage_dns = false if @manage_dns == UNSET_VALUE
237
+ end
238
+
239
+ # Aliases for ssh_key for beautiful semantic.
240
+ def ssh_keys=(value)
241
+ @ssh_key = value
242
+ end
243
+
244
+ alias_method :ssh_key_id=, :ssh_keys=
245
+ alias_method :ssh_key_ids=, :ssh_keys=
246
+ alias_method :ssh_key_name=, :ssh_keys=
247
+ alias_method :ssh_key_names=, :ssh_keys=
248
+
249
+ def validate(machine)
250
+ errors = []
251
+
252
+ errors << I18n.t("vagrant_softlayer.config.api_key_required") if !@api_key
253
+ errors << I18n.t("vagrant_softlayer.config.username_required") if !@username
254
+
255
+ errors << I18n.t("vagrant_softlayer.config.domain_required") if !@domain
256
+ errors << I18n.t("vagrant_softlayer.config.ssh_key_required") if !@ssh_key
257
+
258
+ errors << I18n.t("vagrant_softlayer.config.img_guid_os_code_mutually_exclusive") if @image_guid && @operating_system
259
+ errors << I18n.t("vagrant_softlayer.config.img_guid_capacity_mutually_exclusive") if @image_guid && @disk_capacity
260
+
261
+ # Fail if both `vm.hostname` and `provider.hostname` are nil.
262
+ if !@hostname && !machine.config.vm.hostname
263
+ errors << I18n.t("vagrant_softlayer.config.hostname_required")
264
+ end
265
+
266
+ # Fail if a load balancer has been specified without vip, port or destination port.
267
+ unless @load_balancers.empty?
268
+ @load_balancers.each do |lb|
269
+ errors << I18n.t("vagrant_softlayer.config.lb_port_vip_required") unless (lb[:vip] && lb[:port] && lb[:service].destination_port)
270
+ end
271
+ end
272
+
273
+ # Fail if two or more load balancers has been specified with same vip and port.
274
+ if @load_balancers.map { |lb| { :port => lb[:port], :vip => lb[:vip] } }.uniq!
275
+ errors << I18n.t("vagrant_softlayer.config.lb_duplicate")
276
+ end
277
+
278
+ { "SoftLayer" => errors }
279
+ end
280
+ end
281
+ end
282
+ end