vagrant-brightbox 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +15 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +10 -0
- data/LICENSE +8 -0
- data/README.md +217 -0
- data/Rakefile +21 -0
- data/Vagrantfile.example +105 -0
- data/dummy.box +0 -0
- data/example_box/README.md +9 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-brightbox/action/connect_brightbox.rb +53 -0
- data/lib/vagrant-brightbox/action/create_server.rb +137 -0
- data/lib/vagrant-brightbox/action/delete_server.rb +26 -0
- data/lib/vagrant-brightbox/action/forced_halt.rb +27 -0
- data/lib/vagrant-brightbox/action/is_created.rb +18 -0
- data/lib/vagrant-brightbox/action/is_running.rb +18 -0
- data/lib/vagrant-brightbox/action/map_cloud_ip.rb +68 -0
- data/lib/vagrant-brightbox/action/message_already_created.rb +16 -0
- data/lib/vagrant-brightbox/action/message_not_created.rb +16 -0
- data/lib/vagrant-brightbox/action/read_ssh_info.rb +69 -0
- data/lib/vagrant-brightbox/action/read_state.rb +38 -0
- data/lib/vagrant-brightbox/action/start_server.rb +28 -0
- data/lib/vagrant-brightbox/action/sync_folders.rb +58 -0
- data/lib/vagrant-brightbox/action/timed_provision.rb +21 -0
- data/lib/vagrant-brightbox/action/unsupported.rb +18 -0
- data/lib/vagrant-brightbox/action.rb +166 -0
- data/lib/vagrant-brightbox/config.rb +268 -0
- data/lib/vagrant-brightbox/errors.rb +34 -0
- data/lib/vagrant-brightbox/plugin.rb +73 -0
- data/lib/vagrant-brightbox/provider.rb +50 -0
- data/lib/vagrant-brightbox/util/timer.rb +17 -0
- data/lib/vagrant-brightbox/version.rb +5 -0
- data/lib/vagrant-brightbox.rb +18 -0
- data/locales/en.yml +88 -0
- data/spec/vagrant-brightbox/config_spec.rb +179 -0
- data/vagrant-brightbox.gemspec +23 -0
- metadata +122 -0
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
# We depend on Vagrant for development, but we don't add it as a
|
7
|
+
# gem dependency because we expect to be installed within the
|
8
|
+
# Vagrant environment itself using `vagrant plugin`.
|
9
|
+
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
|
10
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
Copyright (c) 2013 Mitchell Hashimoto
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
5
|
+
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
7
|
+
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# Vagrant Brightbox Provider
|
2
|
+
|
3
|
+
This is a [Vagrant](http://www.vagrantup.com) 1.1+ plugin that adds a [Brightbox](http://brightbox.com/)
|
4
|
+
provider to Vagrant, allowing Vagrant to control and provision servers in
|
5
|
+
the Brightbox Cloud
|
6
|
+
|
7
|
+
**Note:** This plugin requires Vagrant 1.1+,
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
* Boot Brightbox Cloud servers.
|
12
|
+
* SSH into the servers.
|
13
|
+
* Provision the servers with any built-in Vagrant provisioner.
|
14
|
+
* Minimal synced folder support via `rsync`.
|
15
|
+
* Define region-specific configurations so Vagrant can manage servers
|
16
|
+
in multiple regions.
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Install using standard Vagrant 1.1+ plugin installation methods. After
|
21
|
+
installing, `vagrant up` and specify the `brightbox` provider. An example is
|
22
|
+
shown below.
|
23
|
+
|
24
|
+
```
|
25
|
+
$ vagrant plugin install vagrant-brightbox
|
26
|
+
...
|
27
|
+
$ vagrant up --provider=brightbox
|
28
|
+
...
|
29
|
+
```
|
30
|
+
|
31
|
+
Of course prior to doing this, you'll need to obtain an Brightbox-compatible
|
32
|
+
box file for Vagrant.
|
33
|
+
|
34
|
+
## Quick Start
|
35
|
+
|
36
|
+
After installing the plugin (instructions above), the quickest way to get
|
37
|
+
started is to actually use a dummy Brightbox box and specify all the details
|
38
|
+
manually within a `config.vm.provider` block. So first, add the dummy
|
39
|
+
box using any name you want:
|
40
|
+
|
41
|
+
```
|
42
|
+
$ vagrant box add dummy https://github.com/NeilW/vagrant-brightbox/raw/master/dummy.box
|
43
|
+
...
|
44
|
+
```
|
45
|
+
|
46
|
+
And then make a Vagrantfile that looks like the following, filling in
|
47
|
+
your information where necessary.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
Vagrant.configure("2") do |config|
|
51
|
+
config.vm.box = "dummy"
|
52
|
+
|
53
|
+
config.vm.provider :brightbox do |brightbox|
|
54
|
+
brightbox.client_id = "YOUR API CLIENT ID"
|
55
|
+
brightbox.secret = "YOUR API SECRET"
|
56
|
+
brightbox.ssh_private_key_path = "PATH TO YOUR PRIVATE KEY"
|
57
|
+
|
58
|
+
brightbox.image_id = "img-q6gc8"
|
59
|
+
brightbox.ssh_username = "ubuntu"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
And then run `vagrant up --provider=brightbox`.
|
65
|
+
|
66
|
+
This will start an Ubuntu 12.04 server in the gb1 region within
|
67
|
+
your account. And assuming your SSH information was filled in properly
|
68
|
+
within your Vagrantfile, SSH and provisioning will work as well.
|
69
|
+
|
70
|
+
Note that normally a lot of this boilerplate is encoded within the box
|
71
|
+
file, but the box file used for the quick start, the "dummy" box, has
|
72
|
+
no preconfigured defaults.
|
73
|
+
|
74
|
+
Instead of having to add our client credentials to each Vagrantfile
|
75
|
+
we can put them in the Fog configuration file. Create a new
|
76
|
+
file at `~/.fog` and add the following:
|
77
|
+
|
78
|
+
```
|
79
|
+
:default:
|
80
|
+
:brightbox_client_id: "your_api_client_id"
|
81
|
+
:brightbox_secret: "your_secret"
|
82
|
+
```
|
83
|
+
|
84
|
+
## Box Format
|
85
|
+
|
86
|
+
Every provider in Vagrant must introduce a custom box format. This
|
87
|
+
provider introduces `brightbox` boxes. You can view an example box in
|
88
|
+
the [example_box/ directory](https://github.com/NeilW/vagrant-brightbox/tree/master/example_box).
|
89
|
+
That directory also contains instructions on how to build a box.
|
90
|
+
|
91
|
+
The box format is basically just the required `metadata.json` file
|
92
|
+
along with a `Vagrantfile` that does default settings for the
|
93
|
+
provider-specific configuration for this provider.
|
94
|
+
|
95
|
+
## Configuration
|
96
|
+
|
97
|
+
This provider exposes quite a few provider-specific configuration options:
|
98
|
+
|
99
|
+
* `client_id` - The api access key for accessing Brightbox in the form 'cli-xxxxx'
|
100
|
+
* `secret` - The api secret access code for accessing Brightbox
|
101
|
+
* `image_id` - The image id to boot, in the form 'img-xxxxx'
|
102
|
+
* `zone` - The zone within the region to launch
|
103
|
+
the server. If nil, it will use the default for this account.
|
104
|
+
* `server_type` - The type of server, such as "nano"
|
105
|
+
* `region` - The region to start the server in, such as "gb1"
|
106
|
+
* `ssh_private_key_path` - The path to the SSH private key. This overrides
|
107
|
+
`config.ssh.private_key_path`.
|
108
|
+
* `ssh_username` - The SSH username, which overrides `config.ssh.username`.
|
109
|
+
* `security_groups` - An array of security groups for the server.
|
110
|
+
|
111
|
+
If you are the collaborator on a number of accounts you can specify which one you want by setting the following options:
|
112
|
+
|
113
|
+
* `username` - User id in the form 'usr-xxxxx'
|
114
|
+
* `password` - The password for the user id
|
115
|
+
* `account` - Create servers in the context of this account - in the form 'acc-xxxxx'
|
116
|
+
|
117
|
+
These can be set like typical provider-specific configuration:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
Vagrant.configure("2") do |config|
|
121
|
+
# ... other stuff
|
122
|
+
|
123
|
+
config.vm.provider :brightbox do |brightbox|
|
124
|
+
brightbox.client_id = "cli-fooxx"
|
125
|
+
brightbox.secret = "barfoobarfoobar"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
In addition to the above top-level configs, you can use the `region_config`
|
131
|
+
method to specify region-specific overrides within your Vagrantfile. Note
|
132
|
+
that the top-level `region` config must always be specified to choose which
|
133
|
+
region you want to actually use, however. This looks like this:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
Vagrant.configure("2") do |config|
|
137
|
+
# ... other stuff
|
138
|
+
|
139
|
+
config.vm.provider :brightbox do |brightbox|
|
140
|
+
brightbox.client_id = "foo"
|
141
|
+
brightbox.secret = "bar"
|
142
|
+
brightbox.region = "gb1"
|
143
|
+
|
144
|
+
# Simply region config
|
145
|
+
brightbox.region_config "gb1", :image_id => "img-mvunm"
|
146
|
+
|
147
|
+
# More comprehensive region config
|
148
|
+
brightbox.region_config "gb1" do |region|
|
149
|
+
region.image_id = "img-mvunm"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
The region-specific configurations will override the top-level
|
156
|
+
configurations when that region is used. They otherwise inherit
|
157
|
+
the top-level configurations, as you would probably expect.
|
158
|
+
|
159
|
+
## Networks
|
160
|
+
|
161
|
+
By default each brightbox is created and mapped to a cloud ip so that
|
162
|
+
you can access it over the public network.
|
163
|
+
|
164
|
+
However this can exhaust your allocation of cloud ips if you have several servers. Therefore a couple of networking options are supported.
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
# Switch off cloud ip mapping and access servers over the IPv4 private
|
168
|
+
# network - useful if you are running Vagrant from another cloud server.
|
169
|
+
config.vm.network :private_network
|
170
|
+
|
171
|
+
# Switch off cloud ip mapping and access servers over IPv6.
|
172
|
+
config.vm.network :public_network, ipv6: true
|
173
|
+
```
|
174
|
+
|
175
|
+
## Synced Folders
|
176
|
+
|
177
|
+
There is minimal support for synced folders. Upon `vagrant up`,
|
178
|
+
`vagrant reload`, and `vagrant provision`, the Brightbox provider will use
|
179
|
+
`rsync` (if available) to uni-directionally sync the folder to
|
180
|
+
the remote machine over SSH.
|
181
|
+
|
182
|
+
This is good enough for all built-in Vagrant provisioners (shell,
|
183
|
+
chef, and puppet) to work!
|
184
|
+
|
185
|
+
## Development
|
186
|
+
|
187
|
+
To work on the `vagrant-brightbox` plugin, clone this repository out, and use
|
188
|
+
[Bundler](http://gembundler.com) to get the dependencies:
|
189
|
+
|
190
|
+
```
|
191
|
+
$ bundle
|
192
|
+
```
|
193
|
+
|
194
|
+
Once you have the dependencies, verify the unit tests pass with `rake`:
|
195
|
+
|
196
|
+
```
|
197
|
+
$ bundle exec rake
|
198
|
+
```
|
199
|
+
|
200
|
+
If those pass, you're ready to start developing the plugin. You can test
|
201
|
+
the plugin without installing it into your Vagrant environment by just
|
202
|
+
creating a `Vagrantfile` in the top level of this directory (it is gitignored)
|
203
|
+
that uses it:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
Vagrant.require_plugin "vagrant-brightbox"
|
207
|
+
|
208
|
+
Vagrant.configure("2") do |config|
|
209
|
+
#Config here
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
and then use bundler to execute Vagrant:
|
214
|
+
|
215
|
+
```
|
216
|
+
$ bundle exec vagrant up --provider=brightbox
|
217
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
# Immediately sync all stdout so that tools like buildbot can
|
6
|
+
# immediately load in the output.
|
7
|
+
$stdout.sync = true
|
8
|
+
$stderr.sync = true
|
9
|
+
|
10
|
+
# Change to the directory of this file.
|
11
|
+
Dir.chdir(File.expand_path("../", __FILE__))
|
12
|
+
|
13
|
+
# This installs the tasks that help with gem creation and
|
14
|
+
# publishing.
|
15
|
+
Bundler::GemHelper.install_tasks
|
16
|
+
|
17
|
+
# Install the `spec` task so that we can run tests.
|
18
|
+
RSpec::Core::RakeTask.new
|
19
|
+
|
20
|
+
# Default task is to run the unit tests
|
21
|
+
task :default => "spec"
|
data/Vagrantfile.example
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.require_plugin "vagrant-brightbox"
|
5
|
+
|
6
|
+
Vagrant.configure("2") do |config|
|
7
|
+
config.vm.box = "dummy"
|
8
|
+
|
9
|
+
config.vm.provider "brightbox" do |brightbox|
|
10
|
+
brightbox.client_id = "cli-xxxxx"
|
11
|
+
brightbox.secret = "abc123"
|
12
|
+
brightbox.ssh_username = "ubuntu"
|
13
|
+
brightbox.ssh_private_key_path = "/home/here/.ssh/id_rsa"
|
14
|
+
brightbox.image_id = "img-77j4h"
|
15
|
+
#brightbox.auth_url = "https://api.gb1.brightbox.com"
|
16
|
+
#brightbox.api_url = brightbox.auth_url
|
17
|
+
#brightbox.region = "gb1"
|
18
|
+
end
|
19
|
+
|
20
|
+
# By default the Brightbox provider maps a cloud ip to each server
|
21
|
+
# created and accesses the server over the public IPv4 network. This
|
22
|
+
# may cause your allocation to be exhausted. Therefore there are a couple
|
23
|
+
# of options.
|
24
|
+
#
|
25
|
+
# Switch off cloud ip allocation and access over the private IPv4
|
26
|
+
# network. Useful if Vagrant is running on another cloud server in the
|
27
|
+
# same region.
|
28
|
+
#
|
29
|
+
# config.vm.network :private_network
|
30
|
+
#
|
31
|
+
# Switch off cloud ip allocation and access over the public IPv6 network
|
32
|
+
#
|
33
|
+
# config.vm.network :public_network, ipv6: true
|
34
|
+
|
35
|
+
config.vm.provision :shell do |s|
|
36
|
+
s.inline=<<-END
|
37
|
+
apt-get install -y -V puppet
|
38
|
+
END
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Enable provisioning with Puppet stand alone. Puppet manifests
|
43
|
+
# are contained in a directory path relative to this Vagrantfile.
|
44
|
+
# You will need to create the manifests directory and a manifest in
|
45
|
+
# the file base.pp in the manifests_path directory.
|
46
|
+
#
|
47
|
+
# An example Puppet manifest to provision the message of the day:
|
48
|
+
#
|
49
|
+
# # group { "puppet":
|
50
|
+
# # ensure => "present",
|
51
|
+
# # }
|
52
|
+
# #
|
53
|
+
# # File { owner => 0, group => 0, mode => 0644 }
|
54
|
+
# #
|
55
|
+
# # file { '/etc/motd':
|
56
|
+
# # content => "Welcome to your Vagrant-built virtual machine!
|
57
|
+
# # Managed by Puppet.\n"
|
58
|
+
# # }
|
59
|
+
#
|
60
|
+
# config.vm.provision :puppet do |puppet|
|
61
|
+
# puppet.manifests_path = "manifests"
|
62
|
+
# puppet.manifest_file = "base.pp"
|
63
|
+
# end
|
64
|
+
|
65
|
+
# Won't work without puppet installed on the image.
|
66
|
+
config.vm.provision :puppet
|
67
|
+
|
68
|
+
# Enable provisioning with chef solo, specifying a cookbooks path, roles
|
69
|
+
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
70
|
+
# some recipes and/or roles.
|
71
|
+
#
|
72
|
+
# config.vm.provision :chef_solo do |chef|
|
73
|
+
# chef.cookbooks_path = "../my-recipes/cookbooks"
|
74
|
+
# chef.roles_path = "../my-recipes/roles"
|
75
|
+
# chef.data_bags_path = "../my-recipes/data_bags"
|
76
|
+
# chef.add_recipe "mysql"
|
77
|
+
# chef.add_role "web"
|
78
|
+
#
|
79
|
+
# # You may also specify custom JSON attributes:
|
80
|
+
# chef.json = { :mysql_password => "foo" }
|
81
|
+
# end
|
82
|
+
|
83
|
+
# Enable provisioning with chef server, specifying the chef server URL,
|
84
|
+
# and the path to the validation key (relative to this Vagrantfile).
|
85
|
+
#
|
86
|
+
# The Opscode Platform uses HTTPS. Substitute your organization for
|
87
|
+
# ORGNAME in the URL and validation key.
|
88
|
+
#
|
89
|
+
# If you have your own Chef Server, use the appropriate URL, which may be
|
90
|
+
# HTTP instead of HTTPS depending on your configuration. Also change the
|
91
|
+
# validation key to validation.pem.
|
92
|
+
#
|
93
|
+
# config.vm.provision :chef_client do |chef|
|
94
|
+
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
95
|
+
# chef.validation_key_path = "ORGNAME-validator.pem"
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# If you're using the Opscode platform, your validator client is
|
99
|
+
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
100
|
+
#
|
101
|
+
# If you have your own Chef Server, the default validation client name is
|
102
|
+
# chef-validator, unless you changed the configuration.
|
103
|
+
#
|
104
|
+
# chef.validation_client_name = "ORGNAME-validator"
|
105
|
+
end
|
data/dummy.box
ADDED
Binary file
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# Vagrant Brightbox Cloud Example Box
|
2
|
+
|
3
|
+
Vagrant providers each require a custom provider-specific box format.
|
4
|
+
This folder shows the example contents of a box for the `brightbox` provider.
|
5
|
+
To turn this into a box:
|
6
|
+
|
7
|
+
```
|
8
|
+
$ tar cvzf bright.box ./metadata.json
|
9
|
+
```
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "fog"
|
2
|
+
require "log4r"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Brightbox
|
6
|
+
module Action
|
7
|
+
# This action connects to Brightbox, verifies credentials work, and
|
8
|
+
# puts the Brightbox connection object into the `:brightbox_compute` key
|
9
|
+
# in the environment.
|
10
|
+
class ConnectBrightbox
|
11
|
+
def initialize(app, env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new("vagrant_brightbox::action::connect_brightbox")
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
# Get the region we're going to booting up in
|
18
|
+
region = env[:machine].provider_config.region
|
19
|
+
|
20
|
+
# Get the configs
|
21
|
+
region_config = env[:machine].provider_config.get_region_config(region)
|
22
|
+
client_id = region_config.client_id
|
23
|
+
client_secret = region_config.secret
|
24
|
+
username = region_config.username
|
25
|
+
password = region_config.password
|
26
|
+
account = region_config.account
|
27
|
+
auth_url = region_config.auth_url
|
28
|
+
api_url = region_config.api_url
|
29
|
+
|
30
|
+
@logger.info("Connecting to Brightbox...")
|
31
|
+
@logger.info("Fog credentials are: #{Fog.credentials.inspect}")
|
32
|
+
fog_options={
|
33
|
+
:provider => :brightbox,
|
34
|
+
:brightbox_auth_url => auth_url,
|
35
|
+
:brightbox_api_url => api_url,
|
36
|
+
:brightbox_client_id => client_id,
|
37
|
+
:brightbox_secret => client_secret,
|
38
|
+
:brightbox_username => username,
|
39
|
+
:brightbox_password => password,
|
40
|
+
:brightbox_account => account,
|
41
|
+
}
|
42
|
+
fog_options.delete_if {|k, v| v.nil? }
|
43
|
+
@logger.info("Fog compute options are: #{fog_options.inspect}")
|
44
|
+
env[:brightbox_compute] = Fog::Compute.new(fog_options)
|
45
|
+
|
46
|
+
@app.call(env)
|
47
|
+
rescue ArgumentError => e
|
48
|
+
raise Errors::FogError, :message => e.message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
require 'vagrant/util/retryable'
|
4
|
+
|
5
|
+
require 'vagrant-brightbox/util/timer'
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Brightbox
|
9
|
+
module Action
|
10
|
+
# This creates the Brightbox Server
|
11
|
+
class CreateServer
|
12
|
+
include Vagrant::Util::Retryable
|
13
|
+
|
14
|
+
def initialize(app, env)
|
15
|
+
@app = app
|
16
|
+
@logger = Log4r::Logger.new("vagrant_brightbox::action::create_server")
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
# Initialize metrics if they haven't been
|
21
|
+
env[:metrics] ||= {}
|
22
|
+
|
23
|
+
# Get the region we're going to booting up in
|
24
|
+
region = env[:machine].provider_config.region
|
25
|
+
|
26
|
+
# Get the configs
|
27
|
+
region_config = env[:machine].provider_config.get_region_config(region)
|
28
|
+
image_id = region_config.image_id
|
29
|
+
zone = region_config.zone
|
30
|
+
server_name = region_config.server_name
|
31
|
+
server_type = region_config.server_type
|
32
|
+
server_groups = region_config.server_groups
|
33
|
+
|
34
|
+
# Launch!
|
35
|
+
env[:ui].info(I18n.t("vagrant_brightbox.launching_server"))
|
36
|
+
env[:ui].info(" -- Type: #{server_type}") if server_type
|
37
|
+
env[:ui].info(" -- Image: #{image_id}") if image_id
|
38
|
+
env[:ui].info(" -- Region: #{region}")
|
39
|
+
env[:ui].info(" -- Name: #{server_name}") if server_name
|
40
|
+
env[:ui].info(" -- Zone: #{zone}") if zone
|
41
|
+
env[:ui].info(" -- Server Groups: #{server_groups.inspect}") if !server_groups.empty?
|
42
|
+
|
43
|
+
begin
|
44
|
+
options = {
|
45
|
+
:image_id => image_id,
|
46
|
+
:name => server_name,
|
47
|
+
:flavor_id => server_type,
|
48
|
+
:zone_id => zone
|
49
|
+
}
|
50
|
+
|
51
|
+
if !server_groups.empty?
|
52
|
+
options[:server_groups] = server_groups
|
53
|
+
end
|
54
|
+
|
55
|
+
server = env[:brightbox_compute].servers.create(options)
|
56
|
+
rescue Excon::Errors::HTTPStatusError => e
|
57
|
+
raise Errors::FogError, :message => e.response
|
58
|
+
end
|
59
|
+
|
60
|
+
# Immediately save the ID since it is created at this point.
|
61
|
+
env[:machine].id = server.id
|
62
|
+
|
63
|
+
# Wait for the server to build
|
64
|
+
env[:metrics]["server_build_time"] = Util::Timer.time do
|
65
|
+
env[:ui].info(I18n.t("vagrant_brightbox.waiting_for_build"))
|
66
|
+
retryable(:on => Fog::Errors::TimeoutError, :tries => 30) do
|
67
|
+
# If we're interrupted don't worry about waiting
|
68
|
+
next if env[:interrupted]
|
69
|
+
|
70
|
+
# Wait for the server to be ready
|
71
|
+
server.wait_for(2) { ready? }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@logger.info("Time for server to build: #{env[:metrics]["server_build_time"]}")
|
76
|
+
|
77
|
+
if !env[:interrupted]
|
78
|
+
@app.call(env)
|
79
|
+
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
|
80
|
+
# Wait for SSH to be ready.
|
81
|
+
env[:ui].info(I18n.t("vagrant_brightbox.waiting_for_ssh"))
|
82
|
+
while true
|
83
|
+
# If we're interrupted then just back out
|
84
|
+
break if env[:interrupted]
|
85
|
+
break if ready?(env[:machine])
|
86
|
+
sleep 2
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
@logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
|
91
|
+
|
92
|
+
# Ready and booted!
|
93
|
+
env[:ui].info(I18n.t("vagrant_brightbox.ready"))
|
94
|
+
end
|
95
|
+
|
96
|
+
# Terminate the instance if we were interrupted
|
97
|
+
terminate(env) if env[:interrupted]
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
# Check if machine is ready, trapping only non-fatal errors
|
102
|
+
def ready?(machine)
|
103
|
+
@logger.info("Checking if SSH is ready or is permanently broken...")
|
104
|
+
@logger.info("Connecting as '#{machine.ssh_info[:username]}'") if machine.ssh_info[:username]
|
105
|
+
# Yes this is cheating.
|
106
|
+
machine.communicate.send(:connect)
|
107
|
+
@logger.info("SSH is ready")
|
108
|
+
true
|
109
|
+
# Fatal errors
|
110
|
+
rescue Vagrant::Errors::SSHAuthenticationFailed
|
111
|
+
raise
|
112
|
+
# Transient errors
|
113
|
+
rescue Vagrant::Errors::VagrantError => e
|
114
|
+
@logger.info("SSH not up: #{e.inspect}")
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
|
118
|
+
def recover(env)
|
119
|
+
return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
|
120
|
+
|
121
|
+
if env[:machine].provider.state.id != :not_created
|
122
|
+
# Undo the import
|
123
|
+
terminate(env)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def terminate(env)
|
128
|
+
destroy_env = env.dup
|
129
|
+
destroy_env.delete(:interrupted)
|
130
|
+
destroy_env[:config_validate] = false
|
131
|
+
destroy_env[:force_confirm_destroy] = true
|
132
|
+
env[:action_runner].run(Action.action_destroy, destroy_env)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Brightbox
|
5
|
+
module Action
|
6
|
+
# This terminates the running server
|
7
|
+
class DeleteServer
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_brightbox::action::delete_server")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
server = env[:brightbox_compute].servers.get(env[:machine].id)
|
15
|
+
|
16
|
+
# Destroy the server and remove the tracking ID
|
17
|
+
env[:ui].info(I18n.t("vagrant_brightbox.deleting_server"))
|
18
|
+
server.destroy
|
19
|
+
env[:machine].id = nil
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Brightbox
|
5
|
+
module Action
|
6
|
+
# This halts the running server via the api
|
7
|
+
class ForcedHalt
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_brightbox::action::forced_halt")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
server = env[:brightbox_compute].servers.get(env[:machine].id)
|
15
|
+
|
16
|
+
if server.ready?
|
17
|
+
# Stop the server.
|
18
|
+
env[:ui].info(I18n.t("vagrant_brightbox.stopping_server"))
|
19
|
+
server.stop
|
20
|
+
end
|
21
|
+
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Brightbox
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is created and branch in the middleware.
|
6
|
+
class IsCreated
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id != :not_created
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Brightbox
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is active and branch in the middleware.
|
6
|
+
class IsRunning
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id == :active
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|