vagrant-chassis-digitalocean 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.
- data/.gitignore +19 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +23 -0
- data/README.md +95 -0
- data/Rakefile +22 -0
- data/box/digital_ocean.box +0 -0
- data/box/metadata.json +3 -0
- data/lib/vagrant-chassis-digitalocean.rb +20 -0
- data/lib/vagrant-chassis-digitalocean/actions.rb +160 -0
- data/lib/vagrant-chassis-digitalocean/actions/check_state.rb +19 -0
- data/lib/vagrant-chassis-digitalocean/actions/create.rb +96 -0
- data/lib/vagrant-chassis-digitalocean/actions/destroy.rb +35 -0
- data/lib/vagrant-chassis-digitalocean/actions/modify_provision_path.rb +38 -0
- data/lib/vagrant-chassis-digitalocean/actions/power_off.rb +33 -0
- data/lib/vagrant-chassis-digitalocean/actions/power_on.rb +34 -0
- data/lib/vagrant-chassis-digitalocean/actions/rebuild.rb +52 -0
- data/lib/vagrant-chassis-digitalocean/actions/reload.rb +31 -0
- data/lib/vagrant-chassis-digitalocean/actions/setup_key.rb +58 -0
- data/lib/vagrant-chassis-digitalocean/actions/setup_sudo.rb +41 -0
- data/lib/vagrant-chassis-digitalocean/actions/setup_user.rb +64 -0
- data/lib/vagrant-chassis-digitalocean/actions/sync_folders.rb +91 -0
- data/lib/vagrant-chassis-digitalocean/commands/rebuild.rb +23 -0
- data/lib/vagrant-chassis-digitalocean/config.rb +62 -0
- data/lib/vagrant-chassis-digitalocean/errors.rb +37 -0
- data/lib/vagrant-chassis-digitalocean/helpers/client.rb +88 -0
- data/lib/vagrant-chassis-digitalocean/helpers/result.rb +40 -0
- data/lib/vagrant-chassis-digitalocean/plugin.rb +26 -0
- data/lib/vagrant-chassis-digitalocean/provider.rb +100 -0
- data/lib/vagrant-chassis-digitalocean/version.rb +5 -0
- data/locales/en.yml +84 -0
- data/test/Vagrantfile +38 -0
- data/test/cookbooks/test/recipes/default.rb +1 -0
- data/test/scripts/provision.sh +3 -0
- data/test/test.sh +14 -0
- data/test/test_id_rsa +27 -0
- data/test/test_id_rsa.pub +1 -0
- data/vagrant-chassis-digitalocean.gemspec +21 -0
- metadata +137 -0
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2013 John Bender
|
2
|
+
Copyright (c) 2013 Shawn Dahlen
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
Digital Ocean Vagrant Provider For Chassis
|
2
|
+
==========================================
|
3
|
+
`vagrant-chassis-digitalocean` is a provider plugin for Vagrant that supports the
|
4
|
+
management of [Digital Ocean](https://www.digitalocean.com/) droplets
|
5
|
+
(instances) that setup WordPress using [Chassis](https://github.com/Chassis/Chassis/).
|
6
|
+
|
7
|
+
**NOTE:** This plugin is based on the amazing work of the [vagrant-digitalocean
|
8
|
+
](https://github.com/smdahlen/vagrant-digitalocean) plugin
|
9
|
+
|
10
|
+
Current features include:
|
11
|
+
- create and destroy droplets
|
12
|
+
- power on and off droplets
|
13
|
+
- rebuild a droplet
|
14
|
+
- setup a SSH public key for authentication
|
15
|
+
- create a new user account during droplet creation
|
16
|
+
|
17
|
+
The provider has been tested with Vagrant 1.1.5+ using Ubuntu 12.04 and
|
18
|
+
CentOS 6.3 guest operating systems.
|
19
|
+
|
20
|
+
Install
|
21
|
+
-------
|
22
|
+
Installation of the provider requires two steps:
|
23
|
+
|
24
|
+
1. Install the provider plugin using the Vagrant command-line interface:
|
25
|
+
|
26
|
+
$ vagrant plugin install vagrant-chassis-digitalocean
|
27
|
+
|
28
|
+
|
29
|
+
**NOTE:** If you are using a Mac, you may need to install a CA bundle to enable SSL
|
30
|
+
communication with the Digital Ocean API. It is recommended to first install
|
31
|
+
[Homebrew](http://mxcl.github.io/homebrew/). With Homebrew installed, run
|
32
|
+
the following command to install the bundle:
|
33
|
+
|
34
|
+
$ brew install curl-ca-bundle
|
35
|
+
|
36
|
+
Once the bundle is installed, add the following environment variable to your
|
37
|
+
`.bash_profile` script and `source` it:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
export SSL_CERT_FILE=/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt
|
41
|
+
```
|
42
|
+
|
43
|
+
Configure
|
44
|
+
---------
|
45
|
+
Once the provider has been installed, you will need to configure your [Chassis](https://github.com/Chassis/Chassis/) project
|
46
|
+
to use it. You can use your we recommend adding your Digital Ocean details in your projects `config.yaml` or `config.local.yaml` file:
|
47
|
+
```bash
|
48
|
+
digitalocean:
|
49
|
+
client_id: YOUR_CLIENT_ID
|
50
|
+
api_key: YOUR_API_KEY
|
51
|
+
region: 'Singapore 1'
|
52
|
+
size: '512MB'
|
53
|
+
image: 'Ubuntu 12.10 x32'
|
54
|
+
```
|
55
|
+
|
56
|
+
Run
|
57
|
+
---
|
58
|
+
After creating your project's `Vagrantfile` with the required configuration
|
59
|
+
attributes described above, you may create a new droplet with the following
|
60
|
+
command:
|
61
|
+
|
62
|
+
$ vagrant up --provider=digital_ocean
|
63
|
+
|
64
|
+
This command will create a new droplet, setup your SSH key for authentication,
|
65
|
+
create a new user account, and run the provisioners you have configured.
|
66
|
+
|
67
|
+
**Supported Commands**
|
68
|
+
|
69
|
+
The provider supports the following Vagrant sub-commands:
|
70
|
+
- `vagrant destroy` - Destroys the droplet instance.
|
71
|
+
- `vagrant ssh` - Logs into the droplet instance using the configured user
|
72
|
+
account.
|
73
|
+
- `vagrant halt` - Powers off the droplet instance.
|
74
|
+
- `vagrant provision` - Runs the configured provisioners and rsyncs any
|
75
|
+
specified `config.vm.synced_folder`.
|
76
|
+
- `vagrant reload` - Reboots the droplet instance.
|
77
|
+
- `vagrant rebuild` - Destroys the droplet instance and recreates it with the
|
78
|
+
same IP address is was assigned to previously.
|
79
|
+
- `vagrant status` - Outputs the status (active, off, not created) for the
|
80
|
+
droplet instance.
|
81
|
+
|
82
|
+
Contribute
|
83
|
+
----------
|
84
|
+
To contribute, clone the repository, and use [Bundler](http://gembundler.com)
|
85
|
+
to install dependencies:
|
86
|
+
|
87
|
+
$ bundle
|
88
|
+
|
89
|
+
To run the provider's tests:
|
90
|
+
|
91
|
+
$ bundle exec rake test
|
92
|
+
|
93
|
+
You can now make modifications. Running `vagrant` within the Bundler
|
94
|
+
environment will ensure that plugins installed in your Vagrant
|
95
|
+
environment are not loaded.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bundler/gem_helper'
|
2
|
+
|
3
|
+
namespace :gem do
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
end
|
6
|
+
|
7
|
+
task :test do
|
8
|
+
result = sh 'bash test/test.sh'
|
9
|
+
|
10
|
+
if result
|
11
|
+
puts 'Success!'
|
12
|
+
else
|
13
|
+
puts 'Failure!'
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def env
|
19
|
+
['DO_CLIENT_ID', 'DO_API_KEY', 'VAGRANT_LOG'].inject('') do |acc, key|
|
20
|
+
acc += "#{key}=#{ENV[key] || 'error'} "
|
21
|
+
end
|
22
|
+
end
|
Binary file
|
data/box/metadata.json
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'vagrant-digitalocean/version'
|
2
|
+
require 'vagrant-digitalocean/plugin'
|
3
|
+
require 'vagrant-digitalocean/errors'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module DigitalOcean
|
7
|
+
def self.source_root
|
8
|
+
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.public_key(private_key_path)
|
12
|
+
File.read("#{private_key_path}.pub")
|
13
|
+
rescue
|
14
|
+
raise Errors::PublicKeyError, :path => "#{private_key_path}.pub"
|
15
|
+
end
|
16
|
+
|
17
|
+
I18n.load_path << File.expand_path('locales/en.yml', source_root)
|
18
|
+
I18n.reload!
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'vagrant-digitalocean/actions/check_state'
|
2
|
+
require 'vagrant-digitalocean/actions/create'
|
3
|
+
require 'vagrant-digitalocean/actions/destroy'
|
4
|
+
require 'vagrant-digitalocean/actions/power_off'
|
5
|
+
require 'vagrant-digitalocean/actions/power_on'
|
6
|
+
require 'vagrant-digitalocean/actions/rebuild'
|
7
|
+
require 'vagrant-digitalocean/actions/reload'
|
8
|
+
require 'vagrant-digitalocean/actions/setup_user'
|
9
|
+
require 'vagrant-digitalocean/actions/setup_sudo'
|
10
|
+
require 'vagrant-digitalocean/actions/setup_key'
|
11
|
+
require 'vagrant-digitalocean/actions/sync_folders'
|
12
|
+
require 'vagrant-digitalocean/actions/modify_provision_path'
|
13
|
+
|
14
|
+
module VagrantPlugins
|
15
|
+
module DigitalOcean
|
16
|
+
module Actions
|
17
|
+
include Vagrant::Action::Builtin
|
18
|
+
|
19
|
+
def self.destroy
|
20
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
21
|
+
builder.use ConfigValidate
|
22
|
+
builder.use Call, CheckState do |env, b|
|
23
|
+
case env[:machine_state]
|
24
|
+
when :not_created
|
25
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
26
|
+
else
|
27
|
+
b.use Call, DestroyConfirm do |env2, b2|
|
28
|
+
if env2[:result]
|
29
|
+
b2.use Destroy
|
30
|
+
b2.use ProvisionerCleanup if defined?(ProvisionerCleanup)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.ssh
|
39
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
40
|
+
builder.use ConfigValidate
|
41
|
+
builder.use Call, CheckState do |env, b|
|
42
|
+
case env[:machine_state]
|
43
|
+
when :active
|
44
|
+
b.use SSHExec
|
45
|
+
when :off
|
46
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.off')
|
47
|
+
when :not_created
|
48
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.ssh_run
|
55
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
56
|
+
builder.use ConfigValidate
|
57
|
+
builder.use Call, CheckState do |env, b|
|
58
|
+
case env[:machine_state]
|
59
|
+
when :active
|
60
|
+
b.use SSHRun
|
61
|
+
when :off
|
62
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.off')
|
63
|
+
when :not_created
|
64
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.provision
|
71
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
72
|
+
builder.use ConfigValidate
|
73
|
+
builder.use Call, CheckState do |env, b|
|
74
|
+
case env[:machine_state]
|
75
|
+
when :active
|
76
|
+
b.use Provision
|
77
|
+
b.use ModifyProvisionPath
|
78
|
+
b.use SyncFolders
|
79
|
+
when :off
|
80
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.off')
|
81
|
+
when :not_created
|
82
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.up
|
89
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
90
|
+
builder.use ConfigValidate
|
91
|
+
builder.use Call, CheckState do |env, b|
|
92
|
+
case env[:machine_state]
|
93
|
+
when :active
|
94
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.already_active')
|
95
|
+
when :off
|
96
|
+
b.use PowerOn
|
97
|
+
b.use provision
|
98
|
+
when :not_created
|
99
|
+
b.use SetupKey
|
100
|
+
b.use Create
|
101
|
+
b.use SetupSudo
|
102
|
+
b.use SetupUser
|
103
|
+
b.use provision
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.halt
|
110
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
111
|
+
builder.use ConfigValidate
|
112
|
+
builder.use Call, CheckState do |env, b|
|
113
|
+
case env[:machine_state]
|
114
|
+
when :active
|
115
|
+
b.use PowerOff
|
116
|
+
when :off
|
117
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.already_off')
|
118
|
+
when :not_created
|
119
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.reload
|
126
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
127
|
+
builder.use ConfigValidate
|
128
|
+
builder.use Call, CheckState do |env, b|
|
129
|
+
case env[:machine_state]
|
130
|
+
when :active
|
131
|
+
b.use Reload
|
132
|
+
b.use provision
|
133
|
+
when :off
|
134
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.off')
|
135
|
+
when :not_created
|
136
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.rebuild
|
143
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
144
|
+
builder.use ConfigValidate
|
145
|
+
builder.use Call, CheckState do |env, b|
|
146
|
+
case env[:machine_state]
|
147
|
+
when :active, :off
|
148
|
+
b.use Rebuild
|
149
|
+
b.use SetupSudo
|
150
|
+
b.use SetupUser
|
151
|
+
b.use provision
|
152
|
+
when :not_created
|
153
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.not_created')
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DigitalOcean
|
3
|
+
module Actions
|
4
|
+
class CheckState
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
@machine = env[:machine]
|
8
|
+
@logger = Log4r::Logger.new('vagrant::digitalocean::check_state')
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:machine_state] = @machine.state.id
|
13
|
+
@logger.info "Machine state is '#{@machine.state.id}'"
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'vagrant-digitalocean/helpers/client'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class Create
|
7
|
+
include Helpers::Client
|
8
|
+
include Vagrant::Util::Retryable
|
9
|
+
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@machine = env[:machine]
|
13
|
+
@client = client
|
14
|
+
@logger = Log4r::Logger.new('vagrant::digitalocean::create')
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
ssh_key_id = env[:ssh_key_id]
|
19
|
+
|
20
|
+
size_id = @client
|
21
|
+
.request('/sizes')
|
22
|
+
.find_id(:sizes, :name => @machine.provider_config.size)
|
23
|
+
|
24
|
+
image_id = @client
|
25
|
+
.request('/images')
|
26
|
+
.find_id(:images, :name => @machine.provider_config.image)
|
27
|
+
|
28
|
+
region_id = @client
|
29
|
+
.request('/regions')
|
30
|
+
.find_id(:regions, :name => @machine.provider_config.region)
|
31
|
+
|
32
|
+
# submit new droplet request
|
33
|
+
result = @client.request('/droplets/new', {
|
34
|
+
:size_id => size_id,
|
35
|
+
:region_id => region_id,
|
36
|
+
:image_id => image_id,
|
37
|
+
:name => @machine.config.vm.hostname || @machine.name,
|
38
|
+
:ssh_key_ids => ssh_key_id,
|
39
|
+
:private_networking => @machine.provider_config.private_networking,
|
40
|
+
:backups_enabled => @machine.provider_config.backups_enabled
|
41
|
+
})
|
42
|
+
|
43
|
+
# wait for request to complete
|
44
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.creating')
|
45
|
+
@client.wait_for_event(env, result['droplet']['event_id'])
|
46
|
+
|
47
|
+
# assign the machine id for reference in other commands
|
48
|
+
@machine.id = result['droplet']['id'].to_s
|
49
|
+
|
50
|
+
# refresh droplet state with provider and output ip address
|
51
|
+
droplet = Provider.droplet(@machine, :refresh => true)
|
52
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.droplet_ip', {
|
53
|
+
:ip => droplet['ip_address']
|
54
|
+
})
|
55
|
+
if droplet['private_ip_address']
|
56
|
+
env[:ui].info I18n.t('vagrant_digital_ocean.info.droplet_private_ip', {
|
57
|
+
:ip => droplet['private_ip_address']
|
58
|
+
})
|
59
|
+
end
|
60
|
+
|
61
|
+
# wait for ssh to be ready
|
62
|
+
switch_user = @machine.provider_config.setup?
|
63
|
+
user = @machine.config.ssh.username
|
64
|
+
@machine.config.ssh.username = 'root' if switch_user
|
65
|
+
|
66
|
+
retryable(:tries => 120, :sleep => 10) do
|
67
|
+
next if env[:interrupted]
|
68
|
+
raise 'not ready' if !@machine.communicate.ready?
|
69
|
+
end
|
70
|
+
|
71
|
+
@machine.config.ssh.username = user
|
72
|
+
|
73
|
+
@app.call(env)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Both the recover and terminate are stolen almost verbatim from
|
77
|
+
# the Vagrant AWS provider up action
|
78
|
+
def recover(env)
|
79
|
+
return if env['vagrant.error'].is_a?(Vagrant::Errors::VagrantError)
|
80
|
+
|
81
|
+
if @machine.state.id != :not_created
|
82
|
+
terminate(env)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def terminate(env)
|
87
|
+
destroy_env = env.dup
|
88
|
+
destroy_env.delete(:interrupted)
|
89
|
+
destroy_env[:config_validate] = false
|
90
|
+
destroy_env[:force_confirm_destroy] = true
|
91
|
+
env[:action_runner].run(Actions.destroy, destroy_env)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|