vagrant-profitbricks 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/Appraisals +35 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +18 -0
- data/LICENSE +202 -0
- data/README.md +268 -0
- data/RELEASE.md +15 -0
- data/Rakefile +21 -0
- data/Vagrantfile +30 -0
- data/bootstrap.cmd +16 -0
- data/dummy.box +36 -0
- data/example_box/README.md +13 -0
- data/example_box/metadata.json +3 -0
- data/features/provision.feature +36 -0
- data/features/steps/sdk_steps.rb +13 -0
- data/features/steps/server_steps.rb +25 -0
- data/features/support/env.rb +35 -0
- data/features/support/fog_mock.rb +17 -0
- data/features/vagrant-profitbricks.feature +66 -0
- data/lib/vagrant-profitbricks.rb +53 -0
- data/lib/vagrant-profitbricks/action.rb +166 -0
- data/lib/vagrant-profitbricks/action/connect_profitbricks.rb +39 -0
- data/lib/vagrant-profitbricks/action/create_image.rb +53 -0
- data/lib/vagrant-profitbricks/action/create_server.rb +194 -0
- data/lib/vagrant-profitbricks/action/delete_server.rb +43 -0
- data/lib/vagrant-profitbricks/action/is_created.rb +16 -0
- data/lib/vagrant-profitbricks/action/list_flavors.rb +20 -0
- data/lib/vagrant-profitbricks/action/list_images.rb +20 -0
- data/lib/vagrant-profitbricks/action/list_keypairs.rb +20 -0
- data/lib/vagrant-profitbricks/action/list_networks.rb +20 -0
- data/lib/vagrant-profitbricks/action/list_servers.rb +21 -0
- data/lib/vagrant-profitbricks/action/message_already_created.rb +16 -0
- data/lib/vagrant-profitbricks/action/message_not_created.rb +16 -0
- data/lib/vagrant-profitbricks/action/read_ssh_info.rb +49 -0
- data/lib/vagrant-profitbricks/action/read_state.rb +39 -0
- data/lib/vagrant-profitbricks/action/run_init_script.rb +28 -0
- data/lib/vagrant-profitbricks/command/create_image.rb +21 -0
- data/lib/vagrant-profitbricks/command/flavors.rb +21 -0
- data/lib/vagrant-profitbricks/command/images.rb +33 -0
- data/lib/vagrant-profitbricks/command/keypairs.rb +21 -0
- data/lib/vagrant-profitbricks/command/list_images.rb +21 -0
- data/lib/vagrant-profitbricks/command/networks.rb +21 -0
- data/lib/vagrant-profitbricks/command/root.rb +79 -0
- data/lib/vagrant-profitbricks/command/servers.rb +21 -0
- data/lib/vagrant-profitbricks/config.rb +152 -0
- data/lib/vagrant-profitbricks/errors.rb +39 -0
- data/lib/vagrant-profitbricks/plugin.rb +44 -0
- data/lib/vagrant-profitbricks/provider.rb +50 -0
- data/lib/vagrant-profitbricks/version.rb +5 -0
- data/locales/en.yml +124 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/vagrant-profitbricks/actions/list_flavors_spec.rb +48 -0
- data/spec/vagrant-profitbricks/actions/list_images_spec.rb +48 -0
- data/spec/vagrant-profitbricks/config_spec.rb +150 -0
- data/vagrant-profitbricks.gemspec +25 -0
- metadata +164 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
require "fog/profitbricks"
|
2
|
+
require "log4r"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProfitBricks
|
6
|
+
module Action
|
7
|
+
# This action connects to ProfitBricks and verifies that the credentials work
|
8
|
+
class ConnectProfitBricks
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant_profitbricks::action::connect_profitbricks")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
# Get the configs
|
16
|
+
config = env[:machine].provider_config
|
17
|
+
password = config.password
|
18
|
+
username = config.username
|
19
|
+
|
20
|
+
params = {
|
21
|
+
:provider => 'ProfitBricks',
|
22
|
+
:profitbricks_password => password,
|
23
|
+
:profitbricks_username => username
|
24
|
+
}
|
25
|
+
|
26
|
+
if config.profitbricks_url
|
27
|
+
@logger.info("Connecting to ProfitBricks profitbricks_url...")
|
28
|
+
params[:profitbricks_url] = config.profitbricks_url
|
29
|
+
end
|
30
|
+
|
31
|
+
env[:profitbricks_compute] = Fog::Compute.new params
|
32
|
+
@logger.info("env[:profitbricks_compute]: " + env[:profitbricks_compute].to_s)
|
33
|
+
|
34
|
+
@app.call(env)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "fog/profitbricks"
|
2
|
+
require "log4r"
|
3
|
+
|
4
|
+
require 'vagrant/util/retryable'
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module ProfitBricks
|
8
|
+
module Action
|
9
|
+
# Creates an Image
|
10
|
+
class CreateImage
|
11
|
+
include Vagrant::Util::Retryable
|
12
|
+
|
13
|
+
attr_reader :env
|
14
|
+
|
15
|
+
def initialize(app, env)
|
16
|
+
@app, @env = app, env
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.creating_image"))
|
21
|
+
|
22
|
+
server = env[:profitbricks_compute].servers.get(env[:machine].id)
|
23
|
+
|
24
|
+
config = env[:machine].provider_config
|
25
|
+
image_name = config.server_name || env[:machine].name
|
26
|
+
|
27
|
+
image = server.create_image(image_name)
|
28
|
+
|
29
|
+
retryable(:on => Fog::Errors::TimeoutError, :tries => 200) do
|
30
|
+
# If we're interrupted don't worry about waiting
|
31
|
+
next if env[:interrupted]
|
32
|
+
|
33
|
+
env[:ui].clear_line
|
34
|
+
env[:ui].report_progress(image.progress, 100, false)
|
35
|
+
|
36
|
+
begin
|
37
|
+
image.wait_for(5) { ready? }
|
38
|
+
rescue RuntimeError => e
|
39
|
+
# If we don't have an error about a state transition, then
|
40
|
+
# we just move on.
|
41
|
+
raise if e.message !~ /should have transitioned/
|
42
|
+
raise Errors::CreateBadState, :state => server.state
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.image_ready"))
|
47
|
+
|
48
|
+
@app.call(env)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require "fog/profitbricks"
|
2
|
+
require "log4r"
|
3
|
+
|
4
|
+
require 'vagrant/util/retryable'
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module ProfitBricks
|
8
|
+
module Action
|
9
|
+
# This creates the ProfitBricks server.
|
10
|
+
class CreateServer
|
11
|
+
include Vagrant::Util::Retryable
|
12
|
+
|
13
|
+
def initialize(app, env)
|
14
|
+
@app = app
|
15
|
+
@compute = env[:profitbricks_compute]
|
16
|
+
@logger = Log4r::Logger.new("vagrant_profitbricks::action::create_server")
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
# Get the ProfitBricks configs
|
21
|
+
config = env[:machine].provider_config
|
22
|
+
machine_config = env[:machine].config
|
23
|
+
begin
|
24
|
+
communicator = machine_config.vm.communicator ||= :ssh
|
25
|
+
rescue NoMethodError
|
26
|
+
communicator = :ssh
|
27
|
+
end
|
28
|
+
|
29
|
+
# Figure out the Data Center ID,
|
30
|
+
datacenter = find_matching(@compute.datacenters, config.datacenter_id)
|
31
|
+
# in case datacenter is not found try to create new one.
|
32
|
+
# New datacenter is created if provided with name that is not regex or id
|
33
|
+
if config.datacenter_id && !datacenter && !config.datacenter_id.is_a?(Regexp) && (config.datacenter_id =~ /[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}/).nil?
|
34
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.creating_datacenter", :name => config.datacenter_id, :location => config.location))
|
35
|
+
datacenter = @compute.datacenters.create(:name => config.datacenter_id, :location => config.location)
|
36
|
+
|
37
|
+
end
|
38
|
+
raise Errors::NoMatchingDatacenter if !datacenter
|
39
|
+
|
40
|
+
# Find the flavor
|
41
|
+
if config.flavor
|
42
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.finding_flavor"))
|
43
|
+
flavor = find_matching(@compute.flavors, config.flavor)
|
44
|
+
raise Errors::NoMatchingFlavor if !flavor
|
45
|
+
end
|
46
|
+
|
47
|
+
# Find the image
|
48
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.finding_image"))
|
49
|
+
env[:ui].info(I18n.t("config.image: #{config.image}"))
|
50
|
+
env[:ui].info(I18n.t("datacenter.location: #{datacenter.location}"))
|
51
|
+
images = @compute.images.all
|
52
|
+
image = find_matching_image(images, config.image, datacenter.location)
|
53
|
+
|
54
|
+
# Figure out the name for the server
|
55
|
+
server_name = config.server_name || env[:machine].name
|
56
|
+
|
57
|
+
# Prepare volume values
|
58
|
+
vol_name = server_name.to_s + "_volume" if server_name
|
59
|
+
vol_size = config.profitbricks_volume_size ? config.profitbricks_volume_size : 5
|
60
|
+
vol_image = image.id if image
|
61
|
+
vol_type = config.volume_type
|
62
|
+
vol_licence_type = config.volume_licence_type if config.volume_licence_type
|
63
|
+
vol_ssh_keys = config.volume_ssh_keys if config.volume_ssh_keys
|
64
|
+
vol_availability_zone = config.volume_availability_zone
|
65
|
+
vol_image_password = config.image_password if config.image_password
|
66
|
+
|
67
|
+
volume = {
|
68
|
+
:name => vol_name,
|
69
|
+
:size => vol_size,
|
70
|
+
:type => vol_type,
|
71
|
+
:availability_zone => vol_availability_zone
|
72
|
+
}
|
73
|
+
|
74
|
+
if vol_image
|
75
|
+
volume[:image] = vol_image
|
76
|
+
elsif vol_licence_type
|
77
|
+
volume[:licence_type] = vol_licence_type
|
78
|
+
else
|
79
|
+
raise Errors::ImageOrLicenceTypeMustBeProvided
|
80
|
+
end
|
81
|
+
|
82
|
+
if vol_ssh_keys
|
83
|
+
volume[:ssh_keys] = vol_ssh_keys
|
84
|
+
elsif vol_image_password
|
85
|
+
volume[:image_password] = vol_image_password
|
86
|
+
else
|
87
|
+
raise Errors::ImageOrLicenceTypeMustBeProvided
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
# create LAN if it does not exist, and create a NIC on that LAN
|
93
|
+
lan_id = config.lan_id
|
94
|
+
lan = @compute.lans.get(datacenter.id, config.lan_id)
|
95
|
+
|
96
|
+
if !lan || lan.id.end_with?('/lans')
|
97
|
+
lan_name = server_name.to_s + "_lan" if server_name
|
98
|
+
lan = @compute.lans.create(:datacenter_id => datacenter.id, :name => lan_name, :public => true)
|
99
|
+
lan_id = lan.id
|
100
|
+
end
|
101
|
+
|
102
|
+
nic_name = server_name.to_s + "_nic" if server_name
|
103
|
+
nic = {
|
104
|
+
:name => nic_name,
|
105
|
+
:lan => lan_id,
|
106
|
+
:dhcp => true,
|
107
|
+
:nat => config.nat
|
108
|
+
}
|
109
|
+
|
110
|
+
# Output the settings we're going to use to the user
|
111
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.launching_server"))
|
112
|
+
env[:ui].info(" -- Data Center ID: #{datacenter.id}")
|
113
|
+
env[:ui].info(" -- Name: #{server_name}")
|
114
|
+
env[:ui].info(" -- Volume Name: #{vol_name}")
|
115
|
+
env[:ui].info(" -- Image: #{image.name}") if image
|
116
|
+
|
117
|
+
server_cores = nil
|
118
|
+
server_ram = nil
|
119
|
+
|
120
|
+
if flavor
|
121
|
+
env[:ui].info(" -- Flavor: #{flavor.name}")
|
122
|
+
server_cores = flavor.cores
|
123
|
+
server_ram = flavor.ram
|
124
|
+
elsif config.profitbricks_ram && config.profitbricks_cores
|
125
|
+
env[:ui].info(" -- Server cores: #{config.profitbricks_cores}")
|
126
|
+
env[:ui].info(" -- Server ram: #{config.profitbricks_ram } MB")
|
127
|
+
server_cores = config.profitbricks_cores
|
128
|
+
server_ram = config.profitbricks_ram
|
129
|
+
else
|
130
|
+
raise Errors::NoMatchingFlavor
|
131
|
+
end
|
132
|
+
|
133
|
+
# Create the server
|
134
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.creating_server"))
|
135
|
+
server = @compute.servers.create(:datacenter_id => datacenter.id,
|
136
|
+
:name => server_name,
|
137
|
+
:cores => server_cores,
|
138
|
+
:ram => server_ram,
|
139
|
+
:cpu_family => config.cpu_family,
|
140
|
+
:volumes => [volume],
|
141
|
+
:nics => [nic]
|
142
|
+
)
|
143
|
+
server.wait_for { ready? }
|
144
|
+
|
145
|
+
# Store the ID right away so we can track it
|
146
|
+
env[:machine].id = server.id
|
147
|
+
|
148
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.ready"))
|
149
|
+
@app.call(env)
|
150
|
+
end
|
151
|
+
|
152
|
+
protected
|
153
|
+
|
154
|
+
# This method finds a matching _thing_ in a collection of
|
155
|
+
# _things_. This works matching if the ID or NAME equals to
|
156
|
+
# `name`. Or, if `name` is a regexp, a partial match is chosen
|
157
|
+
# as well.
|
158
|
+
def find_matching(collection, name)
|
159
|
+
item = collection.find do |single|
|
160
|
+
single.id == name ||
|
161
|
+
single.name == name ||
|
162
|
+
(name.is_a?(Regexp) && name =~ single.name)
|
163
|
+
end
|
164
|
+
|
165
|
+
item
|
166
|
+
end
|
167
|
+
|
168
|
+
# This method finds a matching _thing_ in a collection of
|
169
|
+
# _things_. This works matching if the ID or NAME equals to
|
170
|
+
# `name`. Or, if `name` is a regexp, a partial match is chosen
|
171
|
+
# as well.
|
172
|
+
def find_matching_image(collection, name, location)
|
173
|
+
location = location ? location : 'us/las'
|
174
|
+
item = collection.find do |image|
|
175
|
+
image.location == location &&
|
176
|
+
image.image_type == 'HDD' &&
|
177
|
+
(image.name == name || image.id == name ||
|
178
|
+
(name.is_a?(Regexp) && image.name =~ name))
|
179
|
+
end
|
180
|
+
|
181
|
+
item
|
182
|
+
end
|
183
|
+
|
184
|
+
# Ported from Vagrant::UI, but scoped to the machine's UI
|
185
|
+
def report_server_progress(machine, progress)
|
186
|
+
machine.ui.clear_line
|
187
|
+
line = "Progress: #{progress}"
|
188
|
+
|
189
|
+
machine.ui.info(line, new_line: false)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ProfitBricks
|
5
|
+
module Action
|
6
|
+
# This deletes the running server, if there is one.
|
7
|
+
class DeleteServer
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_profitbricks::action::delete_server")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
compute = env[:profitbricks_compute]
|
15
|
+
server_id = env[:machine].id
|
16
|
+
server = begin
|
17
|
+
compute.servers.get(server_id)
|
18
|
+
rescue
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
if server.nil?
|
23
|
+
@logger.warn "Unable to find server #{server_id}..."
|
24
|
+
env[:ui].warn(I18n.t('vagrant_profitbricks.errors.server_not_found'))
|
25
|
+
env[:machine].id = nil
|
26
|
+
else
|
27
|
+
@logger.info "Deleting server #{server_id}..."
|
28
|
+
env[:ui].info(I18n.t("vagrant_profitbricks.deleting_server"))
|
29
|
+
|
30
|
+
server.attached_volumes.each do |vol_info|
|
31
|
+
volume = compute.volumes.get(vol_info['id'])
|
32
|
+
volume.delete if volume
|
33
|
+
end
|
34
|
+
server.delete
|
35
|
+
env[:machine].id = nil
|
36
|
+
|
37
|
+
@app.call(env)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProfitBricks
|
3
|
+
module Action
|
4
|
+
class IsCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:result] = env[:machine].state.id != :not_created
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProfitBricks
|
3
|
+
module Action
|
4
|
+
class ListFlavors
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
compute_service = env[:profitbricks_compute]
|
11
|
+
env[:ui].info ('%-36s %s' % ['Flavor ID', 'Flavor Name'])
|
12
|
+
compute_service.flavors.sort_by(&:id).each do |flavor|
|
13
|
+
env[:ui].info ('%-36s %s' % [flavor.id, flavor.name])
|
14
|
+
end
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProfitBricks
|
3
|
+
module Action
|
4
|
+
class ListImages
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
compute_service = env[:profitbricks_compute]
|
11
|
+
env[:ui].info ('%-36s %s' % ['Image ID', 'Image Name'])
|
12
|
+
compute_service.images.sort_by(&:name).each do |image|
|
13
|
+
env[:ui].info ('%-36s %s' % [image.id.to_s, image.name])
|
14
|
+
end
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProfitBricks
|
3
|
+
module Action
|
4
|
+
class ListKeyPairs
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
compute_service = env[:profitbricks_compute]
|
11
|
+
env[:ui].info ('%s' % ['KeyPair Name'])
|
12
|
+
compute_service.key_pairs.sort_by(&:name).each do |keypair|
|
13
|
+
env[:ui].info ('%s' % [keypair.name])
|
14
|
+
end
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProfitBricks
|
3
|
+
module Action
|
4
|
+
class ListInterfaces
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
compute_service = env[:profitbricks_compute]
|
11
|
+
env[:ui].info ('%-36s %-24s %s' % ['Lan Id', 'NIC IPs', 'Internet'])
|
12
|
+
compute_service.interfaces.sort_by(&:server_id).each do |network|
|
13
|
+
env[:ui].info ('%-36s %-24s %s' % [network.lan_id, network.ips, network.internet_access])
|
14
|
+
end
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module ProfitBricks
|
3
|
+
module Action
|
4
|
+
class ListServers
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
compute_service = env[:profitbricks_compute]
|
11
|
+
env[:ui].info ('%-20s %-20s %s' % ['Server Name', 'State', 'IPv4 address'])
|
12
|
+
compute_service.servers.sort_by(&:name).each do |server|
|
13
|
+
ip = server.interfaces[0] ? server.interfaces[0].ips : "-"
|
14
|
+
env[:ui].info ('%-20s %-20s %s' % [server.name, server.state, ip])
|
15
|
+
end
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|