vagrant-softlayer 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Code Climate](https://codeclimate.com/github/audiolize/vagrant-softlayer.png)](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
|
+
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/audiolize/vagrant-softlayer/trend.png)](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
|