vagrant-chassis-digitalocean 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +19 -0
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE.txt +23 -0
  5. data/README.md +95 -0
  6. data/Rakefile +22 -0
  7. data/box/digital_ocean.box +0 -0
  8. data/box/metadata.json +3 -0
  9. data/lib/vagrant-chassis-digitalocean.rb +20 -0
  10. data/lib/vagrant-chassis-digitalocean/actions.rb +160 -0
  11. data/lib/vagrant-chassis-digitalocean/actions/check_state.rb +19 -0
  12. data/lib/vagrant-chassis-digitalocean/actions/create.rb +96 -0
  13. data/lib/vagrant-chassis-digitalocean/actions/destroy.rb +35 -0
  14. data/lib/vagrant-chassis-digitalocean/actions/modify_provision_path.rb +38 -0
  15. data/lib/vagrant-chassis-digitalocean/actions/power_off.rb +33 -0
  16. data/lib/vagrant-chassis-digitalocean/actions/power_on.rb +34 -0
  17. data/lib/vagrant-chassis-digitalocean/actions/rebuild.rb +52 -0
  18. data/lib/vagrant-chassis-digitalocean/actions/reload.rb +31 -0
  19. data/lib/vagrant-chassis-digitalocean/actions/setup_key.rb +58 -0
  20. data/lib/vagrant-chassis-digitalocean/actions/setup_sudo.rb +41 -0
  21. data/lib/vagrant-chassis-digitalocean/actions/setup_user.rb +64 -0
  22. data/lib/vagrant-chassis-digitalocean/actions/sync_folders.rb +91 -0
  23. data/lib/vagrant-chassis-digitalocean/commands/rebuild.rb +23 -0
  24. data/lib/vagrant-chassis-digitalocean/config.rb +62 -0
  25. data/lib/vagrant-chassis-digitalocean/errors.rb +37 -0
  26. data/lib/vagrant-chassis-digitalocean/helpers/client.rb +88 -0
  27. data/lib/vagrant-chassis-digitalocean/helpers/result.rb +40 -0
  28. data/lib/vagrant-chassis-digitalocean/plugin.rb +26 -0
  29. data/lib/vagrant-chassis-digitalocean/provider.rb +100 -0
  30. data/lib/vagrant-chassis-digitalocean/version.rb +5 -0
  31. data/locales/en.yml +84 -0
  32. data/test/Vagrantfile +38 -0
  33. data/test/cookbooks/test/recipes/default.rb +1 -0
  34. data/test/scripts/provision.sh +3 -0
  35. data/test/test.sh +14 -0
  36. data/test/test_id_rsa +27 -0
  37. data/test/test_id_rsa.pub +1 -0
  38. data/vagrant-chassis-digitalocean.gemspec +21 -0
  39. metadata +137 -0
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ test/.vagrant
18
+ tmp
19
+ .idea/
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ Changelog
2
+ =========
3
+
4
+ 0.5.1
5
+ -----
6
+ - added confirmation for `vagrant destroy` [tmatilai]
7
+ - added `ProvisionerCleanup` middleware to destroy action [tmatilai]
8
+ - fixed break from destroy action [tmatilai]
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git', :tag => 'v1.4.0'
4
+ gem 'rake'
5
+ gemspec
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,3 @@
1
+ {
2
+ "provider": "digital_ocean"
3
+ }
@@ -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