vagrant-softlayer 0.1.0 → 0.2.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.
- data/CHANGELOG.md +9 -0
- data/LICENSE +20 -20
- data/README.md +10 -0
- data/Rakefile +6 -6
- data/lib/vagrant-softlayer/action/destroy_instance.rb +2 -2
- data/lib/vagrant-softlayer/action/join_load_balancer.rb +95 -0
- data/lib/vagrant-softlayer/action/load_balancer_cleanup.rb +44 -0
- data/lib/vagrant-softlayer/action/update_dns.rb +35 -37
- data/lib/vagrant-softlayer/action.rb +24 -16
- data/lib/vagrant-softlayer/config.rb +53 -2
- data/lib/vagrant-softlayer/errors.rb +4 -0
- data/lib/vagrant-softlayer/util/load_balancer.rb +103 -0
- data/lib/vagrant-softlayer/util/network.rb +34 -3
- data/lib/vagrant-softlayer/util/warden.rb +1 -1
- data/lib/vagrant-softlayer/version.rb +1 -1
- data/locales/en.yml +24 -0
- data/spec/vagrant-softlayer/config_spec.rb +72 -1
- data/vagrant-softlayer.gemspec +53 -53
- metadata +8 -4
data/CHANGELOG.md
ADDED
data/LICENSE
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2013 audiolize
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
-
this software and associated documentation files (the "Software"), to deal in
|
7
|
-
the Software without restriction, including without limitation the rights to
|
8
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
-
subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 audiolize
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Vagrant SoftLayer Provider
|
2
2
|
|
3
|
+
[](https://codeclimate.com/github/audiolize/vagrant-softlayer)
|
4
|
+
|
3
5
|
This is a [Vagrant](http://www.vagrantup.com) 1.3+ plugin that adds a [SoftLayer](http://www.softlayer.com)
|
4
6
|
provider to Vagrant, allowing Vagrant to control and provision SoftLayer CCI instances.
|
5
7
|
|
@@ -102,6 +104,10 @@ Parameter | Description | Default | Required
|
|
102
104
|
------------ | ------------------------------------- | ------- | --------
|
103
105
|
`manage_dns` | Add/remove A record on create/destroy | false | no
|
104
106
|
|
107
|
+
### Join Local Load Balancers
|
108
|
+
|
109
|
+
See [Join load balancers](https://github.com/audiolize/vagrant-softlayer/wiki/Join-load-balancers).
|
110
|
+
|
105
111
|
### Instance Configuration
|
106
112
|
|
107
113
|
Parameter | Description | Default | Required
|
@@ -231,3 +237,7 @@ Use bundler to execute Vagrant:
|
|
231
237
|
```
|
232
238
|
$ bundle exec vagrant up --provider=softlayer
|
233
239
|
```
|
240
|
+
|
241
|
+
|
242
|
+
[](https://bitdeli.com/free "Bitdeli Badge")
|
243
|
+
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require 'rspec/core/rake_task'
|
3
|
-
|
4
|
-
RSpec::Core::RakeTask.new
|
5
|
-
|
6
|
-
task :default => "spec"
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new
|
5
|
+
|
6
|
+
task :default => "spec"
|
@@ -10,12 +10,12 @@ module VagrantPlugins
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def call(env)
|
13
|
-
@app.call(env)
|
14
|
-
|
15
13
|
env[:ui].info I18n.t("vagrant_softlayer.vm.destroying")
|
16
14
|
|
17
15
|
sl_warden { env[:sl_machine].deleteObject }
|
18
16
|
env[:machine].id = nil
|
17
|
+
|
18
|
+
@app.call(env)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module SoftLayer
|
3
|
+
module Action
|
4
|
+
# Look for defined load balancers and perform join operations.
|
5
|
+
class JoinLoadBalancer
|
6
|
+
include Util::LoadBalancer
|
7
|
+
include Util::Network
|
8
|
+
include Util::Warden
|
9
|
+
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant_softlayer::action::join_load_balancer")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
@env = env
|
17
|
+
|
18
|
+
if enabled?
|
19
|
+
setup
|
20
|
+
prepare
|
21
|
+
join!
|
22
|
+
rebalance!
|
23
|
+
end
|
24
|
+
|
25
|
+
@app.call(@env)
|
26
|
+
end
|
27
|
+
|
28
|
+
def append_service_group(cfg, idx)
|
29
|
+
{}.tap do |virtual_server|
|
30
|
+
virtual_server["allocation"] = 1
|
31
|
+
virtual_server["port"] = cfg[:port]
|
32
|
+
virtual_server["serviceGroups"] = [
|
33
|
+
{
|
34
|
+
"routingMethodId" => (@enums["Routing_Method"][cfg[:method]] || 10),
|
35
|
+
"routingTypeId" => (@enums["Routing_Type"][cfg[:type]] || 3),
|
36
|
+
"services" => []
|
37
|
+
}
|
38
|
+
]
|
39
|
+
@load_balancers[idx]["virtualServers"] << virtual_server
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def join!
|
44
|
+
@pending = []
|
45
|
+
|
46
|
+
until @queue.empty?
|
47
|
+
job = @queue.pop
|
48
|
+
merge(job[:cfg], job[:idx])
|
49
|
+
end
|
50
|
+
|
51
|
+
# Perform the API calls for join.
|
52
|
+
@load_balancers.each_with_index do |lb, idx|
|
53
|
+
next unless @pending[idx]
|
54
|
+
@logger.debug("Updating VIP #{lb['id']} with: #{lb['virtualServers']}")
|
55
|
+
vip_id = @services["VirtualIpAddress"].object_with_id(lb["id"])
|
56
|
+
sl_warden { vip_id.editObject("virtualServers" => lb["virtualServers"]) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def merge(cfg, idx)
|
61
|
+
# Get the service group. Create it if not found.
|
62
|
+
sg = @load_balancers[idx]["virtualServers"].find(lambda { append_service_group(cfg, idx) }) { |g| g["port"] == cfg[:port] }
|
63
|
+
# Get the IP address ID of the current machine.
|
64
|
+
ip_id = ip_address_id(@env)
|
65
|
+
unless sg["serviceGroups"].first["services"].index { |s| s["ipAddressId"] == ip_id }
|
66
|
+
@logger.debug("Merging service: #{cfg[:service]}")
|
67
|
+
# Add the service to the group.
|
68
|
+
sg["serviceGroups"].first["services"] << {
|
69
|
+
"enabled" => 1,
|
70
|
+
"ipAddressId" => ip_id,
|
71
|
+
"groupReferences" => [ { "weight" => cfg[:service].weight } ],
|
72
|
+
"healthChecks" => [ { "healthCheckTypeId" => (@enums["Health_Check_Type"][cfg[:service].health_check] || 21) } ],
|
73
|
+
"port" => cfg[:service].destination_port
|
74
|
+
}
|
75
|
+
# Mark the load balancer object as pending update
|
76
|
+
@pending[idx] = true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def prepare
|
81
|
+
@env[:ui].info I18n.t("vagrant_softlayer.vm.joining_load_balancers")
|
82
|
+
|
83
|
+
# For each definition, check if the load balancer exists and enqueue
|
84
|
+
# the join operation.
|
85
|
+
@queue = []
|
86
|
+
@env[:machine].provider_config.load_balancers.each do |cfg|
|
87
|
+
idx = @load_balancers.index { |lb| lb["ipAddress"]["ipAddress"] == cfg[:vip] }
|
88
|
+
raise Errors::SLLoadBalancerNotFound unless idx
|
89
|
+
@queue << { :cfg => cfg, :idx => idx }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module SoftLayer
|
3
|
+
module Action
|
4
|
+
# Cleanup orphaned virtual servers from load balancers.
|
5
|
+
class LoadBalancerCleanup
|
6
|
+
include Util::LoadBalancer
|
7
|
+
include Util::Warden
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant_softlayer::action::load_balancer_cleanup")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
@env = env
|
16
|
+
|
17
|
+
if enabled?
|
18
|
+
setup
|
19
|
+
cleanup!
|
20
|
+
rebalance!
|
21
|
+
end
|
22
|
+
|
23
|
+
@app.call(@env)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cleanup!
|
27
|
+
@env[:ui].info I18n.t("vagrant_softlayer.vm.load_balancer_cleanup")
|
28
|
+
|
29
|
+
# Keep it safe here. We delete a virtual server only if
|
30
|
+
# no services exist on any service group. In the future,
|
31
|
+
# we will find a way to selectively delete empty service groups.
|
32
|
+
@load_balancers.each do |load_balancer|
|
33
|
+
load_balancer["virtualServers"].each do |vs|
|
34
|
+
if vs["serviceGroups"].inject(0) { |sum, sg| sum + sg["services"].count } == 0
|
35
|
+
@logger.debug("Found empty virtual server (ID #{vs['id']}). Deleting.")
|
36
|
+
sl_warden { @services["VirtualServer"].object_with_id(vs["id"]).deleteObject }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -16,11 +16,30 @@ module VagrantPlugins
|
|
16
16
|
def call(env)
|
17
17
|
@env = env
|
18
18
|
|
19
|
-
|
19
|
+
update_dns
|
20
20
|
|
21
21
|
@app.call(@env)
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
+
def add_record
|
25
|
+
template = {
|
26
|
+
"data" => ip_address(@env),
|
27
|
+
"domainId" => @dns_zone["id"],
|
28
|
+
"host" => hostname(@env),
|
29
|
+
"ttl" => 86400,
|
30
|
+
"type" => "a"
|
31
|
+
}
|
32
|
+
@env[:ui].info I18n.t("vagrant_softlayer.vm.creating_dns_record")
|
33
|
+
@logger.debug("Creating DNS A record for #{template['host']}.#{@dns_zone[:name]} (IP address #{template['data']}).")
|
34
|
+
resource = sl_warden { @resource.createObject(template) }
|
35
|
+
self.dns_id = resource["id"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete_record
|
39
|
+
@env[:ui].info I18n.t("vagrant_softlayer.vm.deleting_dns_record")
|
40
|
+
@logger.debug("Deleting stored DNS A record (ID #{self.dns_id}).")
|
41
|
+
warn_msg = lambda { @env[:ui].warn I18n.t("vagrant_softlayer.errors.dns_record_not_found") }
|
42
|
+
sl_warden(warn_msg) { @resource.object_with_id(self.dns_id).deleteObject }
|
24
43
|
end
|
25
44
|
|
26
45
|
def dns_id
|
@@ -45,49 +64,28 @@ module VagrantPlugins
|
|
45
64
|
end
|
46
65
|
end
|
47
66
|
|
48
|
-
def
|
67
|
+
def update_dns
|
49
68
|
unless @env[:machine].provider_config.manage_dns
|
50
69
|
@logger.debug("Not managing DNS. Going ahead.")
|
51
70
|
return
|
52
71
|
end
|
53
72
|
|
54
|
-
|
55
|
-
|
73
|
+
# Lookup the DNS zone
|
74
|
+
zone = ::SoftLayer::Service.new("SoftLayer_Dns_Domain", @env[:sl_credentials])
|
56
75
|
domain = @env[:machine].provider_config.domain
|
57
|
-
@logger.debug("Looking for #{domain} zone into the SoftLayer zone list.")
|
58
|
-
dns_zone_obj = sl_warden { dns_zone.getByDomainName(domain).first }
|
59
|
-
raise Errors::SLDNSZoneNotFound, :zone => domain unless dns_zone_obj
|
60
|
-
@logger.debug("Found DNS zone: #{dns_zone_obj.inspect}")
|
61
|
-
return dns_zone_obj
|
62
|
-
end
|
63
|
-
|
64
|
-
def update_dns
|
65
|
-
unless @env[:machine].provider_config.manage_dns
|
66
|
-
@logger.debug("Not managing DNS. Going ahead.")
|
67
|
-
return
|
68
|
-
end
|
69
76
|
|
70
|
-
|
77
|
+
@logger.debug("Looking for #{domain} zone into the SoftLayer zone list.")
|
78
|
+
@dns_zone = sl_warden { zone.getByDomainName(domain).first }
|
79
|
+
raise Errors::SLDNSZoneNotFound, :zone => domain unless @dns_zone
|
80
|
+
@logger.debug("Found DNS zone: #{@dns_zone.inspect}")
|
71
81
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
"host" => hostname,
|
80
|
-
"ttl" => 86400,
|
81
|
-
"type" => "a"
|
82
|
-
}
|
83
|
-
@env[:ui].info I18n.t("vagrant_softlayer.vm.creating_dns_record")
|
84
|
-
@logger.debug("Creating DNS A record for #{hostname}.#{@env[:dns_zone][:name]} (IP address #{res_template['data']}).")
|
85
|
-
new_rr = sl_warden { dns_resource.createObject(res_template) }
|
86
|
-
self.dns_id = new_rr["id"]
|
87
|
-
when :machine_action_destroy
|
88
|
-
@env[:ui].info I18n.t("vagrant_softlayer.vm.deleting_dns_record")
|
89
|
-
@logger.debug("Deleting stored DNS A record (ID #{self.dns_id}).")
|
90
|
-
sl_warden { dns_resource.object_with_id(self.dns_id).deleteObject }
|
82
|
+
# Add or remove the resource record
|
83
|
+
@resource = ::SoftLayer::Service.new("SoftLayer_Dns_Domain_ResourceRecord", @env[:sl_credentials])
|
84
|
+
case @env[:machine_action]
|
85
|
+
when :up
|
86
|
+
add_record unless self.dns_id
|
87
|
+
when :destroy
|
88
|
+
delete_record
|
91
89
|
end
|
92
90
|
end
|
93
91
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "pathname"
|
2
|
+
require "vagrant-softlayer/util/load_balancer"
|
2
3
|
require "vagrant-softlayer/util/network"
|
3
4
|
require "vagrant-softlayer/util/warden"
|
4
5
|
|
@@ -21,8 +22,10 @@ module VagrantPlugins
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
b2.use SetupSoftLayer
|
24
|
-
b2.use DestroyInstance
|
25
25
|
b2.use UpdateDNS
|
26
|
+
b2.use DestroyInstance
|
27
|
+
b2.use LoadBalancerCleanup
|
28
|
+
b2.use ProvisionerCleanup
|
26
29
|
else
|
27
30
|
b2.use Message, :warn, "vagrant_softlayer.vm.not_destroying"
|
28
31
|
end
|
@@ -157,9 +160,10 @@ module VagrantPlugins
|
|
157
160
|
b1.use SetupSoftLayer
|
158
161
|
b1.use Provision
|
159
162
|
b1.use SyncFolders
|
160
|
-
b1.use UpdateDNS
|
161
163
|
b1.use CreateInstance
|
162
164
|
b1.use WaitForProvision
|
165
|
+
b1.use UpdateDNS
|
166
|
+
b1.use JoinLoadBalancer
|
163
167
|
b1.use WaitForCommunicator
|
164
168
|
else
|
165
169
|
b1.use Call, Is, :halted do |env2, b2|
|
@@ -168,6 +172,8 @@ module VagrantPlugins
|
|
168
172
|
b2.use Provision
|
169
173
|
b2.use SyncFolders
|
170
174
|
b2.use StartInstance
|
175
|
+
b2.use UpdateDNS
|
176
|
+
b2.use JoinLoadBalancer
|
171
177
|
b2.use WaitForCommunicator
|
172
178
|
else
|
173
179
|
b2.use Message, :warn, "vagrant_softlayer.vm.already_running"
|
@@ -181,20 +187,22 @@ module VagrantPlugins
|
|
181
187
|
# The autoload farm
|
182
188
|
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
183
189
|
|
184
|
-
autoload :CreateInstance,
|
185
|
-
autoload :DestroyInstance,
|
186
|
-
autoload :Is,
|
187
|
-
autoload :
|
188
|
-
autoload :
|
189
|
-
autoload :
|
190
|
-
autoload :
|
191
|
-
autoload :
|
192
|
-
autoload :
|
193
|
-
autoload :
|
194
|
-
autoload :
|
195
|
-
autoload :
|
196
|
-
autoload :
|
197
|
-
autoload :
|
190
|
+
autoload :CreateInstance, action_root.join("create_instance")
|
191
|
+
autoload :DestroyInstance, action_root.join("destroy_instance")
|
192
|
+
autoload :Is, action_root.join("is")
|
193
|
+
autoload :JoinLoadBalancer, action_root.join("join_load_balancer")
|
194
|
+
autoload :LoadBalancerCleanup, action_root.join("load_balancer_cleanup")
|
195
|
+
autoload :Message, action_root.join("message")
|
196
|
+
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
|
197
|
+
autoload :ReadState, action_root.join("read_state")
|
198
|
+
autoload :RebuildInstance, action_root.join("rebuild_instance")
|
199
|
+
autoload :SetupSoftLayer, action_root.join("setup_softlayer")
|
200
|
+
autoload :StartInstance, action_root.join("start_instance")
|
201
|
+
autoload :StopInstance, action_root.join("stop_instance")
|
202
|
+
autoload :SyncFolders, action_root.join("sync_folders")
|
203
|
+
autoload :UpdateDNS, action_root.join("update_dns")
|
204
|
+
autoload :WaitForProvision, action_root.join("wait_for_provision")
|
205
|
+
autoload :WaitForRebuild, action_root.join("wait_for_rebuild")
|
198
206
|
end
|
199
207
|
end
|
200
208
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
|
1
3
|
module VagrantPlugins
|
2
4
|
module SoftLayer
|
3
5
|
class Config < Vagrant.plugin("2", :config)
|
@@ -58,6 +60,9 @@ module VagrantPlugins
|
|
58
60
|
# The ID of the public VLAN.
|
59
61
|
attr_accessor :vlan_public
|
60
62
|
|
63
|
+
# The load balancers service groups to join.
|
64
|
+
attr_reader :load_balancers
|
65
|
+
|
61
66
|
# Automatically update DNS on create and destroy.
|
62
67
|
attr_accessor :manage_dns
|
63
68
|
|
@@ -83,7 +88,41 @@ module VagrantPlugins
|
|
83
88
|
@vlan_private = UNSET_VALUE
|
84
89
|
@vlan_public = UNSET_VALUE
|
85
90
|
|
86
|
-
@
|
91
|
+
@load_balancers = []
|
92
|
+
@manage_dns = UNSET_VALUE
|
93
|
+
end
|
94
|
+
|
95
|
+
# Set the load balancer service group to join.
|
96
|
+
#
|
97
|
+
# Available options:
|
98
|
+
#
|
99
|
+
# :method => Routing method. Default to round robin.
|
100
|
+
# :port => Load balancer virtual port.
|
101
|
+
# :type => Routing type. Default to TCP.
|
102
|
+
# :vip => Load balancer virtual IP address.
|
103
|
+
#
|
104
|
+
# An optional block will accept parameters for the
|
105
|
+
# balanced service. Available parameters:
|
106
|
+
#
|
107
|
+
# :destination_port => TCP port on the node.
|
108
|
+
# :health_check => Service health check. Default to ping.
|
109
|
+
# :weight => Service weight. Default to 1.
|
110
|
+
#
|
111
|
+
def join_load_balancer(opts = {}, &block)
|
112
|
+
# Defaults
|
113
|
+
opts[:method] ||= "ROUND ROBIN"
|
114
|
+
opts[:type] ||= "TCP"
|
115
|
+
opts[:service] = OpenStruct.new(:destination_port => nil, :health_check => "PING", :weight => 1)
|
116
|
+
|
117
|
+
yield opts[:service] if block_given?
|
118
|
+
|
119
|
+
# Convert all options that belongs to
|
120
|
+
# an enumeration in uppercase.
|
121
|
+
opts[:method].upcase!
|
122
|
+
opts[:type].upcase!
|
123
|
+
opts[:service].health_check.upcase!
|
124
|
+
|
125
|
+
@load_balancers << opts
|
87
126
|
end
|
88
127
|
|
89
128
|
def finalize!
|
@@ -148,7 +187,7 @@ module VagrantPlugins
|
|
148
187
|
@manage_dns = false if @manage_dns == UNSET_VALUE
|
149
188
|
end
|
150
189
|
|
151
|
-
# Aliases for ssh_key for beautiful semantic
|
190
|
+
# Aliases for ssh_key for beautiful semantic.
|
152
191
|
def ssh_keys=(value)
|
153
192
|
@ssh_key = value
|
154
193
|
end
|
@@ -171,6 +210,18 @@ module VagrantPlugins
|
|
171
210
|
errors << I18n.t("vagrant_softlayer.config.hostname_required")
|
172
211
|
end
|
173
212
|
|
213
|
+
# Fail if a load balancer has been specified without vip, port or destination port.
|
214
|
+
unless @load_balancers.empty?
|
215
|
+
@load_balancers.each do |lb|
|
216
|
+
errors << I18n.t("vagrant_softlayer.config.lb_port_vip_required") unless (lb[:vip] && lb[:port] && lb[:service].destination_port)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Fail if two or more load balancers has been specified with same vip and port.
|
221
|
+
if @load_balancers.map { |lb| { :port => lb[:port], :vip => lb[:vip] } }.uniq!
|
222
|
+
errors << I18n.t("vagrant_softlayer.config.lb_duplicate")
|
223
|
+
end
|
224
|
+
|
174
225
|
{ "SoftLayer" => errors }
|
175
226
|
end
|
176
227
|
end
|
@@ -17,6 +17,10 @@ module VagrantPlugins
|
|
17
17
|
error_key(:dns_zone_not_found)
|
18
18
|
end
|
19
19
|
|
20
|
+
class SLLoadBalancerNotFound < VagrantSoftLayerError
|
21
|
+
error_key(:load_balancer_not_found)
|
22
|
+
end
|
23
|
+
|
20
24
|
class SLSshKeyNotFound < VagrantSoftLayerError
|
21
25
|
error_key(:ssh_key_not_found)
|
22
26
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module SoftLayer
|
3
|
+
module Util
|
4
|
+
# This mixin contains utility methods for load balancer management.
|
5
|
+
module LoadBalancer
|
6
|
+
# Whether load balancer management is enabled or not.
|
7
|
+
def enabled?
|
8
|
+
if @env[:machine].provider_config.load_balancers.empty?
|
9
|
+
@logger.debug("No load balancer has been defined. Going ahead.")
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
|
13
|
+
# Currently we don't do load balancing for private machines.
|
14
|
+
if @env[:machine].provider_config.private_only
|
15
|
+
@logger.info("Load balancing doesn't work for private machines. Going ahead.")
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get existing stuff.
|
22
|
+
def read_load_balancers
|
23
|
+
mask = [
|
24
|
+
"id",
|
25
|
+
"ipAddress.ipAddress",
|
26
|
+
"virtualServers.serviceGroups.services.groupReferences",
|
27
|
+
"virtualServers.serviceGroups.services.healthChecks"
|
28
|
+
]
|
29
|
+
@logger.debug("Looking for existing load balancers.")
|
30
|
+
@load_balancers = sl_warden { @services["Account"].object_mask(mask).getAdcLoadBalancers }
|
31
|
+
@logger.debug("Got load balancer configuration:")
|
32
|
+
@logger.debug("-- #{@load_balancers}")
|
33
|
+
end
|
34
|
+
|
35
|
+
# For each load balancer, check if total connections
|
36
|
+
# are less than 100% and, if so, rebalance the allocations.
|
37
|
+
def rebalance!
|
38
|
+
read_load_balancers
|
39
|
+
|
40
|
+
@load_balancers.each do |load_balancer|
|
41
|
+
next if load_balancer["virtualServers"].empty?
|
42
|
+
next if 100 == load_balancer["virtualServers"].inject(0) { |sum, vs| sum += vs["allocation"] }
|
43
|
+
|
44
|
+
# Create allocation slots.
|
45
|
+
count = load_balancer["virtualServers"].count
|
46
|
+
allocation = [100 / count] * count
|
47
|
+
(100 % count).times { |i| allocation[i] += 1 }
|
48
|
+
|
49
|
+
# Rebalance allocations.
|
50
|
+
load_balancer["virtualServers"].each do |vs|
|
51
|
+
vs["allocation"] = allocation.pop
|
52
|
+
end
|
53
|
+
|
54
|
+
# Update the VIP object.
|
55
|
+
@logger.debug("Rebalancing VIP #{load_balancer['id']}")
|
56
|
+
@logger.debug("-- #{load_balancer}")
|
57
|
+
@services["VirtualIpAddress"].object_with_id(load_balancer["id"]).editObject("virtualServers" => load_balancer["virtualServers"])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Initial setup.
|
62
|
+
def setup
|
63
|
+
# A plethora of service objects is required for managing
|
64
|
+
# load balancers. We instanciate'em all here.
|
65
|
+
@services = {
|
66
|
+
"Account" => ::SoftLayer::Service.new("SoftLayer_Account", @env[:sl_credentials])
|
67
|
+
}
|
68
|
+
[
|
69
|
+
"Health_Check_Type",
|
70
|
+
"Routing_Method",
|
71
|
+
"Routing_Type",
|
72
|
+
"Service",
|
73
|
+
"Service_Group",
|
74
|
+
"VirtualIpAddress",
|
75
|
+
"VirtualServer"
|
76
|
+
].each do |service|
|
77
|
+
@services[service] = ::SoftLayer::Service.new(
|
78
|
+
"SoftLayer_Network_Application_Delivery_Controller_LoadBalancer_#{service}",
|
79
|
+
@env[:sl_credentials]
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
# We create enumerations for the various configurables.
|
84
|
+
@enums = {}
|
85
|
+
[
|
86
|
+
"Health_Check_Type",
|
87
|
+
"Routing_Method",
|
88
|
+
"Routing_Type"
|
89
|
+
].each do |service|
|
90
|
+
{}.tap do |enum|
|
91
|
+
sl_warden { @services[service].getAllObjects }.each do |record|
|
92
|
+
enum[record["name"].upcase] = record["id"]
|
93
|
+
end
|
94
|
+
@enums[service] = enum
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
read_load_balancers
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -2,13 +2,44 @@ module VagrantPlugins
|
|
2
2
|
module SoftLayer
|
3
3
|
module Util
|
4
4
|
module Network
|
5
|
-
# Gets instance
|
5
|
+
# Gets hostname of the instance starting from the environment.
|
6
|
+
def hostname(env)
|
7
|
+
env[:machine].provider_config.hostname || env[:machine].config.vm.hostname
|
8
|
+
end
|
9
|
+
|
10
|
+
# Gets IP address of the instance starting from the environment.
|
6
11
|
#
|
7
12
|
# Returns the private IP address if the instance has been
|
8
13
|
# defined as private only, the public IP address otherwise.
|
9
14
|
def ip_address(env)
|
10
|
-
|
11
|
-
|
15
|
+
ip_address_record(env)[:address]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Gets IP address ID of the instance starting from the environment.
|
19
|
+
#
|
20
|
+
# Returns the private IP address ID if the instance has been
|
21
|
+
# defined as private only, the public IP address ID otherwise.
|
22
|
+
def ip_address_id(env)
|
23
|
+
ip_address_record(env)[:id]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Gets IP address record of the instance starting from the environment.
|
27
|
+
#
|
28
|
+
# Returns an hash with the following structure:
|
29
|
+
#
|
30
|
+
# :address
|
31
|
+
# :id
|
32
|
+
#
|
33
|
+
# Returns the private IP address record if the instance has been
|
34
|
+
# defined as private only, the public IP address record otherwise.
|
35
|
+
def ip_address_record(env)
|
36
|
+
data_type = env[:machine].provider_config.private_only ? "primaryBackendNetworkComponent" : "primaryNetworkComponent"
|
37
|
+
mask = { data_type => { "primaryIpAddressRecord" => ["id", "ipAddress"] } }
|
38
|
+
record = sl_warden { env[:sl_machine].object_mask(mask).getObject }
|
39
|
+
return {
|
40
|
+
:address => record[data_type]["primaryIpAddressRecord"]["ipAddress"],
|
41
|
+
:id => record[data_type]["primaryIpAddressRecord"]["id"]
|
42
|
+
}
|
12
43
|
end
|
13
44
|
|
14
45
|
# Returns SSH keys starting from the configuration parameter.
|
@@ -19,7 +19,7 @@ module VagrantPlugins
|
|
19
19
|
rescue ::OpenSSL::SSL::SSLError
|
20
20
|
raise Errors::SLCertificateError
|
21
21
|
rescue SocketError, ::SoftLayer::SoftLayerAPIException => e
|
22
|
-
if e.class == ::SoftLayer::SoftLayerAPIException && e.message.start_with?("Unable to find object
|
22
|
+
if e.class == ::SoftLayer::SoftLayerAPIException && (e.message.start_with?("Unable to find object") || e.message.start_with?("Object does not exist"))
|
23
23
|
out = rescue_proc.call if rescue_proc
|
24
24
|
if retry_interval > 0
|
25
25
|
sleep retry_interval
|
data/locales/en.yml
CHANGED
@@ -26,6 +26,20 @@ en:
|
|
26
26
|
config.vm.provider :softlayer do |sl|
|
27
27
|
sl.hostname = "vagrant"
|
28
28
|
end
|
29
|
+
lb_duplicate: |-
|
30
|
+
A load balancer service group has been specified multiple
|
31
|
+
times. Only one directive for any { :vip, :port } combination
|
32
|
+
is allowed.
|
33
|
+
lb_port_vip_required: |-
|
34
|
+
For joining a load balancer, you need to specify at least
|
35
|
+
virtual IP address, virtual server port and destination
|
36
|
+
port in the provider section of the Vagrantfile:
|
37
|
+
|
38
|
+
config.vm.provider :softlayer do |sl|
|
39
|
+
sl.join_load_balancer :port => 443, :vip => "1.1.1.1" do |service|
|
40
|
+
service.destination_port = 443
|
41
|
+
end
|
42
|
+
end
|
29
43
|
ssh_key_required: |-
|
30
44
|
At least an SSH key for the instance is required.
|
31
45
|
Please specify it, either using name or id, in the
|
@@ -67,9 +81,15 @@ en:
|
|
67
81
|
Windows example:
|
68
82
|
|
69
83
|
set SSL_CERT_FILE=C:\HashiCorp\Vagrant\embedded\cacert.pem
|
84
|
+
dns_record_not_found: |-
|
85
|
+
The DNS record you're trying to delete has not been found.
|
70
86
|
dns_zone_not_found: |-
|
71
87
|
The DNS zone you're trying to manage (%{zone}) has not been
|
72
88
|
found in the zone list.
|
89
|
+
load_balancer_not_found: |-
|
90
|
+
The load balancer you're trying to join has not been found.
|
91
|
+
|
92
|
+
Please check the configuration parameter for virtual IP address.
|
73
93
|
ssh_key_not_found: |-
|
74
94
|
The SSH key you're trying to set (%{key}) does not exists in the
|
75
95
|
SoftLayer account's keychain.
|
@@ -116,6 +136,10 @@ en:
|
|
116
136
|
Deleting DNS record for the instance...
|
117
137
|
destroying: |-
|
118
138
|
Destroying the SoftLayer instance...
|
139
|
+
joining_load_balancers: |-
|
140
|
+
Joining load balancer(s)...
|
141
|
+
load_balancer_cleanup: |-
|
142
|
+
Running cleanup tasks for load balancers...
|
119
143
|
not_destroying: |-
|
120
144
|
The SoftLayer instance will not be destroyed, since the confirmation
|
121
145
|
was declined.
|
@@ -32,7 +32,8 @@ describe VagrantPlugins::SoftLayer::Config do
|
|
32
32
|
its("vlan_private") { should be_nil }
|
33
33
|
its("vlan_public") { should be_nil }
|
34
34
|
|
35
|
-
its("
|
35
|
+
its("load_balancers") { should eq [] }
|
36
|
+
its("manage_dns") { should be_false }
|
36
37
|
end
|
37
38
|
|
38
39
|
describe "overriding defaults" do
|
@@ -69,6 +70,34 @@ describe VagrantPlugins::SoftLayer::Config do
|
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
73
|
+
describe "joining load balancer" do
|
74
|
+
it "should set weight to 1 by default" do
|
75
|
+
config.join_load_balancer :port => 443, :vip => "1.1.1.1"
|
76
|
+
config.finalize!
|
77
|
+
expect(config.load_balancers.first[:service].weight).to eq(1)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should set passed options" do
|
81
|
+
config.join_load_balancer :foo => "bar", :port => 443, :vip => "1.1.1.1"
|
82
|
+
config.finalize!
|
83
|
+
expect(config.load_balancers.first[:foo]).to eq("bar")
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should set service parameters" do
|
87
|
+
config.join_load_balancer :port => 443, :vip => "1.1.1.1" do |srv|
|
88
|
+
srv.destination_port = 443
|
89
|
+
srv.health_check = "DNS"
|
90
|
+
srv.notes = "Some notes"
|
91
|
+
srv.weight = 9
|
92
|
+
end
|
93
|
+
config.finalize!
|
94
|
+
expect(config.load_balancers.first[:service].destination_port).to eq(443)
|
95
|
+
expect(config.load_balancers.first[:service].health_check).to eq("DNS")
|
96
|
+
expect(config.load_balancers.first[:service].notes).to eq("Some notes")
|
97
|
+
expect(config.load_balancers.first[:service].weight).to eq(9)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
72
101
|
describe "using SL_ environment variables" do
|
73
102
|
before :each do
|
74
103
|
ENV.stub(:[]).with("SL_API_KEY").and_return("env_api_key")
|
@@ -143,6 +172,7 @@ describe VagrantPlugins::SoftLayer::Config do
|
|
143
172
|
|
144
173
|
it "should validate if hostname is not given but config.vm.hostname is set" do
|
145
174
|
config.hostname = nil
|
175
|
+
config.finalize!
|
146
176
|
machine.stub_chain(:config, :vm, :hostname).and_return("vagrant")
|
147
177
|
expect(config.validate(machine)["SoftLayer"]).to have(:no).item
|
148
178
|
end
|
@@ -152,5 +182,46 @@ describe VagrantPlugins::SoftLayer::Config do
|
|
152
182
|
config.finalize!
|
153
183
|
expect(config.validate(machine)["SoftLayer"]).to have(1).item
|
154
184
|
end
|
185
|
+
|
186
|
+
it "should fail if a load balancer is specified without vip" do
|
187
|
+
config.join_load_balancer :port => 443 do |srv|
|
188
|
+
srv.destination_port = 443
|
189
|
+
end
|
190
|
+
config.finalize!
|
191
|
+
expect(config.validate(machine)["SoftLayer"]).to have(1).item
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should fail if a load balancer is specified without port" do
|
195
|
+
config.join_load_balancer :vip => "1.1.1.1" do |srv|
|
196
|
+
srv.destination_port = 443
|
197
|
+
end
|
198
|
+
config.finalize!
|
199
|
+
expect(config.validate(machine)["SoftLayer"]).to have(1).item
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should fail if a load balancer is specified without destination port" do
|
203
|
+
config.join_load_balancer :port => 443, :vip => "1.1.1.1"
|
204
|
+
config.finalize!
|
205
|
+
expect(config.validate(machine)["SoftLayer"]).to have(1).item
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should fail if two load balancers han been defined with same vip and port" do
|
209
|
+
config.join_load_balancer :port => 443, :vip => "1.1.1.1" do |srv|
|
210
|
+
srv.destination_port = 443
|
211
|
+
end
|
212
|
+
config.join_load_balancer :port => 443, :vip => "1.1.1.1" do |srv|
|
213
|
+
srv.destination_port = 8443
|
214
|
+
end
|
215
|
+
config.finalize!
|
216
|
+
expect(config.validate(machine)["SoftLayer"]).to have(1).item
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should validate if a load balancer if specified with vip, port and destination port" do
|
220
|
+
config.join_load_balancer :port => 443, :vip => "1.1.1.1" do |srv|
|
221
|
+
srv.destination_port = 443
|
222
|
+
end
|
223
|
+
config.finalize!
|
224
|
+
expect(config.validate(machine)["SoftLayer"]).to have(:no).item
|
225
|
+
end
|
155
226
|
end
|
156
227
|
end
|
data/vagrant-softlayer.gemspec
CHANGED
@@ -1,53 +1,53 @@
|
|
1
|
-
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
-
require "vagrant-softlayer/version"
|
3
|
-
|
4
|
-
Gem::Specification.new do |spec|
|
5
|
-
spec.name = "vagrant-softlayer"
|
6
|
-
spec.version = VagrantPlugins::SoftLayer::VERSION
|
7
|
-
spec.authors = "Audiolize GmbH"
|
8
|
-
spec.email = ""
|
9
|
-
spec.description = "Enables Vagrant to manages SoftLayer CCI."
|
10
|
-
spec.summary = "Enables Vagrant to manages SoftLayer CCI."
|
11
|
-
|
12
|
-
# The following block of code determines the files that should be included
|
13
|
-
# in the gem. It does this by reading all the files in the directory where
|
14
|
-
# this gemspec is, and parsing out the ignored files from the gitignore.
|
15
|
-
# Note that the entire gitignore(5) syntax is not supported, specifically
|
16
|
-
# the "!" syntax, but it should mostly work correctly.
|
17
|
-
root_path = File.dirname(__FILE__)
|
18
|
-
all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
|
19
|
-
all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
|
20
|
-
gitignore_path = File.join(root_path, ".gitignore")
|
21
|
-
gitignore = File.readlines(gitignore_path)
|
22
|
-
gitignore.map! { |line| line.chomp.strip }
|
23
|
-
gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
|
24
|
-
|
25
|
-
unignored_files = all_files.reject do |file|
|
26
|
-
# Ignore any directories, the gemspec only cares about files
|
27
|
-
next true if File.directory?(file)
|
28
|
-
|
29
|
-
# Ignore any paths that match anything in the gitignore. We do
|
30
|
-
# two tests here:
|
31
|
-
#
|
32
|
-
# - First, test to see if the entire path matches the gitignore.
|
33
|
-
# - Second, match if the basename does, this makes it so that things
|
34
|
-
# like '.DS_Store' will match sub-directories too (same behavior
|
35
|
-
# as git).
|
36
|
-
#
|
37
|
-
gitignore.any? do |ignore|
|
38
|
-
File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
|
39
|
-
File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
spec.files = unignored_files
|
44
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
45
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
46
|
-
spec.require_path = "lib"
|
47
|
-
|
48
|
-
spec.add_dependency "softlayer_api"
|
49
|
-
|
50
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
51
|
-
spec.add_development_dependency "rake"
|
52
|
-
spec.add_development_dependency "rspec"
|
53
|
-
end
|
1
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
+
require "vagrant-softlayer/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "vagrant-softlayer"
|
6
|
+
spec.version = VagrantPlugins::SoftLayer::VERSION
|
7
|
+
spec.authors = "Audiolize GmbH"
|
8
|
+
spec.email = ""
|
9
|
+
spec.description = "Enables Vagrant to manages SoftLayer CCI."
|
10
|
+
spec.summary = "Enables Vagrant to manages SoftLayer CCI."
|
11
|
+
|
12
|
+
# The following block of code determines the files that should be included
|
13
|
+
# in the gem. It does this by reading all the files in the directory where
|
14
|
+
# this gemspec is, and parsing out the ignored files from the gitignore.
|
15
|
+
# Note that the entire gitignore(5) syntax is not supported, specifically
|
16
|
+
# the "!" syntax, but it should mostly work correctly.
|
17
|
+
root_path = File.dirname(__FILE__)
|
18
|
+
all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
|
19
|
+
all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
|
20
|
+
gitignore_path = File.join(root_path, ".gitignore")
|
21
|
+
gitignore = File.readlines(gitignore_path)
|
22
|
+
gitignore.map! { |line| line.chomp.strip }
|
23
|
+
gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
|
24
|
+
|
25
|
+
unignored_files = all_files.reject do |file|
|
26
|
+
# Ignore any directories, the gemspec only cares about files
|
27
|
+
next true if File.directory?(file)
|
28
|
+
|
29
|
+
# Ignore any paths that match anything in the gitignore. We do
|
30
|
+
# two tests here:
|
31
|
+
#
|
32
|
+
# - First, test to see if the entire path matches the gitignore.
|
33
|
+
# - Second, match if the basename does, this makes it so that things
|
34
|
+
# like '.DS_Store' will match sub-directories too (same behavior
|
35
|
+
# as git).
|
36
|
+
#
|
37
|
+
gitignore.any? do |ignore|
|
38
|
+
File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
|
39
|
+
File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
spec.files = unignored_files
|
44
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
45
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
46
|
+
spec.require_path = "lib"
|
47
|
+
|
48
|
+
spec.add_dependency "softlayer_api"
|
49
|
+
|
50
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
51
|
+
spec.add_development_dependency "rake"
|
52
|
+
spec.add_development_dependency "rspec"
|
53
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-softlayer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: softlayer_api
|
@@ -81,6 +81,7 @@ executables: []
|
|
81
81
|
extensions: []
|
82
82
|
extra_rdoc_files: []
|
83
83
|
files:
|
84
|
+
- CHANGELOG.md
|
84
85
|
- dummy.box
|
85
86
|
- example_box/metadata.json
|
86
87
|
- example_box/README.md
|
@@ -88,6 +89,8 @@ files:
|
|
88
89
|
- lib/vagrant-softlayer/action/create_instance.rb
|
89
90
|
- lib/vagrant-softlayer/action/destroy_instance.rb
|
90
91
|
- lib/vagrant-softlayer/action/is.rb
|
92
|
+
- lib/vagrant-softlayer/action/join_load_balancer.rb
|
93
|
+
- lib/vagrant-softlayer/action/load_balancer_cleanup.rb
|
91
94
|
- lib/vagrant-softlayer/action/message.rb
|
92
95
|
- lib/vagrant-softlayer/action/read_ssh_info.rb
|
93
96
|
- lib/vagrant-softlayer/action/read_state.rb
|
@@ -105,6 +108,7 @@ files:
|
|
105
108
|
- lib/vagrant-softlayer/errors.rb
|
106
109
|
- lib/vagrant-softlayer/plugin.rb
|
107
110
|
- lib/vagrant-softlayer/provider.rb
|
111
|
+
- lib/vagrant-softlayer/util/load_balancer.rb
|
108
112
|
- lib/vagrant-softlayer/util/network.rb
|
109
113
|
- lib/vagrant-softlayer/util/warden.rb
|
110
114
|
- lib/vagrant-softlayer/version.rb
|
@@ -131,7 +135,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
135
|
version: '0'
|
132
136
|
segments:
|
133
137
|
- 0
|
134
|
-
hash:
|
138
|
+
hash: 2669020036350751985
|
135
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
140
|
none: false
|
137
141
|
requirements:
|
@@ -140,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
144
|
version: '0'
|
141
145
|
segments:
|
142
146
|
- 0
|
143
|
-
hash:
|
147
|
+
hash: 2669020036350751985
|
144
148
|
requirements: []
|
145
149
|
rubyforge_project:
|
146
150
|
rubygems_version: 1.8.23
|