vagrant-digitalocean 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +7 -0
- data/bin/build.sh +33 -0
- data/box/Vagrantfile +15 -0
- data/box/digital_ocean.box +0 -0
- data/box/metadata.json +3 -0
- data/lib/vagrant-digitalocean/action.rb +77 -0
- data/lib/vagrant-digitalocean/actions/create.rb +103 -0
- data/lib/vagrant-digitalocean/actions/destroy.rb +44 -0
- data/lib/vagrant-digitalocean/actions/read_state.rb +31 -0
- data/lib/vagrant-digitalocean/actions/setup_nfs.rb +55 -0
- data/lib/vagrant-digitalocean/actions/setup_provisioner.rb +30 -0
- data/lib/vagrant-digitalocean/actions/setup_sudo.rb +27 -0
- data/lib/vagrant-digitalocean/actions/setup_user.rb +59 -0
- data/lib/vagrant-digitalocean/config.rb +31 -0
- data/lib/vagrant-digitalocean/errors.rb +23 -0
- data/lib/vagrant-digitalocean/helpers/client.rb +48 -0
- data/lib/vagrant-digitalocean/helpers/file.rb +41 -0
- data/lib/vagrant-digitalocean/helpers/result.rb +40 -0
- data/lib/vagrant-digitalocean/helpers/translator.rb +20 -0
- data/lib/vagrant-digitalocean/plugin.rb +30 -0
- data/lib/vagrant-digitalocean/provider.rb +84 -0
- data/lib/vagrant-digitalocean/version.rb +5 -0
- data/lib/vagrant-digitalocean.rb +19 -0
- data/locales/en.yml +53 -0
- data/scripts/chef/debian.sh +20 -0
- data/scripts/chef/redhat.sh +21 -0
- data/scripts/nfs/debian.sh +4 -0
- data/scripts/nfs/redhat.sh +11 -0
- data/scripts/sudo/redhat.sh +2 -0
- data/vagrant-digitalocean.gemspec +22 -0
- metadata +128 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 John Bender
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Vagrant Digital Ocean
|
2
|
+
|
3
|
+
`vagrant-digitalocean` is a provider plugin for Vagrant that allows the management of [Digital Ocean](https://www.digitalocean.com/) droplets (instances).
|
4
|
+
|
5
|
+
## INSECURE
|
6
|
+
|
7
|
+
As of this writing there is no support for custom keys on the droplets created by this provider. That means anyone with the vagrant keys and the IP of your droplet has root on your machine.
|
8
|
+
|
9
|
+
*Do not use this plugin with sensitive projects*
|
10
|
+
|
11
|
+
## Status
|
12
|
+
|
13
|
+
As of this writing the provider implementation is geared entirely toward a development workflow. That is, Digital Ocean droplets are meant to be used as a replacement for VirtualBox in a server developers workflow.
|
14
|
+
|
15
|
+
## Supported Guests/Hosts
|
16
|
+
|
17
|
+
This project is primarily to support my workflow wich currently only involves Ubuntu and CentOS. It's likely that any unix host will work but I've not tested it. Guests require porting of the nfs, chef, and sudo setup scripts.
|
18
|
+
|
19
|
+
Hosts:
|
20
|
+
|
21
|
+
* Ubuntu 12.04
|
22
|
+
|
23
|
+
Guests:
|
24
|
+
|
25
|
+
* Ubuntu 12.04
|
26
|
+
* CentOS 6
|
27
|
+
|
28
|
+
## Supported Provisioners
|
29
|
+
|
30
|
+
The shell provisioner is supported by default but other provisioners require bootstrapping on the server. Chef is currently the only supported provisioner. Adding support for puppet and others requires adding the install scripts.
|
31
|
+
|
32
|
+
## Installation
|
33
|
+
|
34
|
+
Installation is performed in the prescribed manner for Vagrant 1.1 plugins.
|
35
|
+
|
36
|
+
vagrant plugin install vagrant-digitalocean
|
37
|
+
|
38
|
+
In addition to installing the plugin the default box associated with the provider needs to be installed.
|
39
|
+
|
40
|
+
vagrant box add digital_ocean https://raw.github.com/johnbender/vagrant-digitalocean/master/box/digital_ocean.box
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
To use the Digital Ocean provider you will need to visit the [API access page](https://www.digitalocean.com/api_access) to retrieve the client identifier and API key associated with your account.
|
45
|
+
|
46
|
+
### Config
|
47
|
+
|
48
|
+
Supported provider configuration options are as follows:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Vagrant.configure("2") do |config|
|
52
|
+
config.vm.box = "digital_ocean"
|
53
|
+
|
54
|
+
config.vm.provider :digital_ocean do |vm|
|
55
|
+
vm.client_id = ENV["DO_CLIENT_ID"]
|
56
|
+
vm.api_key = ENV["DO_API_KEY"]
|
57
|
+
vm.image = "Ubuntu 12.04 x32 Server"
|
58
|
+
vm.region = "New York 1"
|
59
|
+
vm.size = "512MB"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
Note that the example contains the default value. The client identifier and API key are pulled from the environment and the other values are the string representations of the droplet configuration options as provided by the [Digital Ocean API](https://www.digitalocean.com/api).
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
1. Fork it
|
69
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
70
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
72
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/build.sh
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# build the gem
|
4
|
+
gem build *.gemspec
|
5
|
+
|
6
|
+
# make the gem available for installation as a vagrant plugin
|
7
|
+
gem install *.gem
|
8
|
+
|
9
|
+
# make sure bsdtar is installed
|
10
|
+
if ! `which bsdtar > /dev/null`; then
|
11
|
+
echo "!! Install bsdtar"
|
12
|
+
exit 1
|
13
|
+
fi
|
14
|
+
|
15
|
+
# install the plugin
|
16
|
+
vagrant plugin install vagrant-digitalocean
|
17
|
+
|
18
|
+
# move into the dummy box dir
|
19
|
+
cd box
|
20
|
+
|
21
|
+
# create the dummy box
|
22
|
+
tar cvzf digital_ocean.box ./metadata.json
|
23
|
+
|
24
|
+
# remove an old version of the dummy box
|
25
|
+
if `vagrant box list | grep -q digital_ocean`; then
|
26
|
+
vagrant box remove digital_ocean digital_ocean
|
27
|
+
fi
|
28
|
+
|
29
|
+
# add the new version of the dummy box
|
30
|
+
vagrant box add digital_ocean digital_ocean.box
|
31
|
+
|
32
|
+
# back out of the box dir
|
33
|
+
cd -
|
data/box/Vagrantfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure("2") do |config|
|
5
|
+
config.vm.box = "digital_ocean"
|
6
|
+
config.vm.synced_folder ".", "/vagrant", :nfs => true
|
7
|
+
|
8
|
+
config.vm.provider :digital_ocean do |vm|
|
9
|
+
vm.client_id = ENV["DO_CLIENT_ID"]
|
10
|
+
vm.api_key = ENV["DO_API_KEY"]
|
11
|
+
vm.image = "Ubuntu 12.04 x32 Server"
|
12
|
+
vm.region = "New York 1"
|
13
|
+
vm.size = "512MB"
|
14
|
+
end
|
15
|
+
end
|
Binary file
|
data/box/metadata.json
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require "vagrant-digitalocean/actions/destroy"
|
2
|
+
require "vagrant-digitalocean/actions/read_state"
|
3
|
+
require "vagrant-digitalocean/actions/setup_provisioner"
|
4
|
+
require "vagrant-digitalocean/actions/setup_nfs"
|
5
|
+
require "vagrant-digitalocean/actions/setup_sudo"
|
6
|
+
require "vagrant-digitalocean/actions/setup_user"
|
7
|
+
require "vagrant-digitalocean/actions/create"
|
8
|
+
|
9
|
+
module VagrantPlugins
|
10
|
+
module DigitalOcean
|
11
|
+
class Action
|
12
|
+
# Include the built-in callable actions, eg SSHExec
|
13
|
+
include Vagrant::Action::Builtin
|
14
|
+
|
15
|
+
def action(name)
|
16
|
+
send(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy
|
20
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
21
|
+
builder.use ConfigValidate
|
22
|
+
builder.use Actions::Destroy
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def read_state
|
27
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
28
|
+
builder.use ConfigValidate
|
29
|
+
builder.use Actions::ReadState
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def ssh
|
34
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
35
|
+
builder.use ConfigValidate
|
36
|
+
builder.use SSHExec
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def provision
|
41
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
42
|
+
builder.use ConfigValidate
|
43
|
+
|
44
|
+
# sort out sudo for redhat, etc
|
45
|
+
builder.use Actions::SetupSudo
|
46
|
+
|
47
|
+
# sort out sudo for redhat, etc
|
48
|
+
builder.use Actions::SetupUser
|
49
|
+
|
50
|
+
# execute provisioners
|
51
|
+
builder.use Provision
|
52
|
+
|
53
|
+
# setup provisioners, comes after Provision to force nfs folders
|
54
|
+
builder.use Actions::SetupProvisioner
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def up
|
59
|
+
# TODO figure out when to exit if the vm is created
|
60
|
+
return Vagrant::Action::Builder.new.tap do |builder|
|
61
|
+
builder.use ConfigValidate
|
62
|
+
|
63
|
+
# build the vm if necessary
|
64
|
+
builder.use Actions::Create
|
65
|
+
|
66
|
+
builder.use provision
|
67
|
+
|
68
|
+
# set the host and remote ips for NFS
|
69
|
+
builder.use Actions::SetupNFS
|
70
|
+
|
71
|
+
# mount the nfs folders which should be all shared folders
|
72
|
+
builder.use NFS
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require "vagrant-digitalocean/helpers/client"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class Create
|
7
|
+
include Vagrant::Util::Retryable
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app, @env = app, env
|
11
|
+
@client = Helpers::Client.new
|
12
|
+
@translator = Helpers::Translator.new("actions.create")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
# if the machine state is created skip
|
17
|
+
if env[:machine].state.id == :active
|
18
|
+
env[:ui].info @translator.t("skip")
|
19
|
+
return @app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO check the content of the key to see if it's changed
|
23
|
+
# TODO use the directory / vm name to qualify the key name
|
24
|
+
begin
|
25
|
+
ssh_key_id = @client
|
26
|
+
.request("/ssh_keys/")
|
27
|
+
.find_id(:ssh_keys, :name => "Vagrant Insecure")
|
28
|
+
rescue Errors::ResultMatchError
|
29
|
+
env[:ui].info @translator.t("create_key")
|
30
|
+
|
31
|
+
key = DigitalOcean.vagrant_key
|
32
|
+
|
33
|
+
result = @client.request("/ssh_keys/new", {
|
34
|
+
:name => "Vagrant Insecure",
|
35
|
+
:ssh_pub_key => key
|
36
|
+
})
|
37
|
+
|
38
|
+
ssh_key_id = result["ssh_key"]["id"]
|
39
|
+
end
|
40
|
+
|
41
|
+
size_id = @client
|
42
|
+
.request("/sizes")
|
43
|
+
.find_id(:sizes, :name => env[:machine].provider_config.size)
|
44
|
+
|
45
|
+
image_id = @client
|
46
|
+
.request("/images", { :filter => "global" })
|
47
|
+
.find_id(:images, :name => env[:machine].provider_config.image)
|
48
|
+
|
49
|
+
region_id = @client
|
50
|
+
.request("/regions")
|
51
|
+
.find_id(:regions, :name => env[:machine].provider_config.region)
|
52
|
+
|
53
|
+
env[:ui].info @translator.t("create_droplet")
|
54
|
+
|
55
|
+
result = @client.request("/droplets/new", {
|
56
|
+
:size_id => size_id,
|
57
|
+
:region_id => region_id,
|
58
|
+
:image_id => image_id,
|
59
|
+
# TODO use the current directory name as a post fix
|
60
|
+
:name => "vagrant",
|
61
|
+
:ssh_key_ids => ssh_key_id
|
62
|
+
})
|
63
|
+
|
64
|
+
# assign the machine id for reference in other commands
|
65
|
+
env[:machine].id = result["droplet"]["id"]
|
66
|
+
|
67
|
+
env[:ui].info @translator.t("wait_active")
|
68
|
+
|
69
|
+
retryable(:tries => 30, :sleep => 10) do
|
70
|
+
# If we're interrupted don't worry about waiting
|
71
|
+
next if env[:interrupted]
|
72
|
+
|
73
|
+
# Wait for the server to be ready
|
74
|
+
raise "not ready" if env[:machine].state.id != :active
|
75
|
+
end
|
76
|
+
|
77
|
+
# signal that the machine has just been created, used in ReadState
|
78
|
+
env[:machine_just_created] = true
|
79
|
+
|
80
|
+
@app.call(env)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Both the recover and terminate are stolen almost verbatim from
|
84
|
+
# the Vagrant AWS provider up action
|
85
|
+
def recover(env)
|
86
|
+
return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
|
87
|
+
|
88
|
+
if env[:machine].state.id != :not_created
|
89
|
+
terminate(env)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def terminate(env)
|
94
|
+
destroy_env = env.dup
|
95
|
+
destroy_env.delete(:interrupted)
|
96
|
+
destroy_env[:config_validate] = false
|
97
|
+
destroy_env[:force_confirm_destroy] = true
|
98
|
+
env[:action_runner].run(ActionDispatch.new.destroy, destroy_env)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "vagrant-digitalocean/helpers/client"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class Destroy
|
7
|
+
include Vagrant::Util::Retryable
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app, @env = app, env
|
11
|
+
@client = Helpers::Client.new
|
12
|
+
@translator = Helpers::Translator.new("actions.destroy")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
# TODO remove the key associated with this machine
|
17
|
+
if [:active, :new].include?(env[:machine].state.id)
|
18
|
+
env[:ui].info @translator.t("destroying")
|
19
|
+
result = @client.request("/droplets/#{env[:machine].id}/destroy")
|
20
|
+
|
21
|
+
env[:ui].info @translator.t("wait_off")
|
22
|
+
|
23
|
+
retryable(:tries => 30, :sleep => 10) do
|
24
|
+
# If we're interrupted don't worry about waiting
|
25
|
+
next if env[:interrupted]
|
26
|
+
|
27
|
+
# Wait for the server to be ready
|
28
|
+
raise "not off" if env[:machine].state.id != :off
|
29
|
+
end
|
30
|
+
else
|
31
|
+
env[:ui].info @translator.t("not_active_or_new")
|
32
|
+
end
|
33
|
+
|
34
|
+
# make sure to remove the export when the machine is destroyed
|
35
|
+
# private in some hosts and requires a send
|
36
|
+
env[:ui].info @translator.t("clean_nfs")
|
37
|
+
env[:host].send(:nfs_cleanup, env[:machine].id)
|
38
|
+
|
39
|
+
@app.call(env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "vagrant-digitalocean/helpers/client"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class ReadState
|
7
|
+
def initialize(app, env)
|
8
|
+
@app, @env = app, env
|
9
|
+
@client = Helpers::Client.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
# If we have a machine id ask the api what the state is
|
14
|
+
if env[:machine].id
|
15
|
+
droplet = @client.request("/droplets/#{env[:machine].id}")["droplet"]
|
16
|
+
|
17
|
+
env[:machine_state] = droplet
|
18
|
+
end
|
19
|
+
|
20
|
+
# no id signals that the machine hasn't yet been created
|
21
|
+
env[:machine_state] ||= {"status" => :not_created}
|
22
|
+
|
23
|
+
# TODO there has to be a better way, see UP for when
|
24
|
+
# :machine_just_created is set
|
25
|
+
env[:machine_state][:just_created] = env[:machine_just_created]
|
26
|
+
@app.call(env)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class SetupNFS
|
7
|
+
include Helpers::File
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app, @env = app, env
|
11
|
+
@translator = Helpers::Translator.new("actions.setup_nfs")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
# set the nfs machine ip
|
16
|
+
env[:nfs_machine_ip] = env[:machine].provider.ssh_info[:host]
|
17
|
+
env[:ui].info @translator.t("machine_ip", :ip => env[:nfs_machine_ip])
|
18
|
+
|
19
|
+
# get the host ip from the local adapters
|
20
|
+
env[:nfs_host_ip] = determine_host_ip.ip_address
|
21
|
+
env[:ui].info @translator.t("host_ip", :ip => env[:nfs_host_ip])
|
22
|
+
|
23
|
+
# make sure the nfs server is setup
|
24
|
+
env[:ui].info @translator.t("install")
|
25
|
+
env[:machine].communicate.execute(nfs_install(env[:machine].guest))
|
26
|
+
|
27
|
+
vm = env[:machine].config.vm
|
28
|
+
|
29
|
+
# force all shard folders to use nfs
|
30
|
+
env[:ui].warn @translator.t("force_shared_folders")
|
31
|
+
folders = vm.synced_folders.keys.each do |key|
|
32
|
+
vm.synced_folders[key][:nfs] = true
|
33
|
+
end
|
34
|
+
|
35
|
+
@app.call(env)
|
36
|
+
end
|
37
|
+
|
38
|
+
# http://stackoverflow.com/questions/5029427/ruby-get-local-ip-nix
|
39
|
+
# TODO this is currently *nix only according to the above post
|
40
|
+
def determine_host_ip
|
41
|
+
Socket.ip_address_list.detect do |intf|
|
42
|
+
intf.ipv4? &&
|
43
|
+
!intf.ipv4_loopback? &&
|
44
|
+
!intf.ipv4_multicast? &&
|
45
|
+
!intf.ipv4_private?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def nfs_install(guest)
|
50
|
+
read_script("nfs", guest)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "vagrant-digitalocean/helpers/file"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class SetupProvisioner
|
7
|
+
include Helpers::File
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app, @env = app, env
|
11
|
+
@translator = Helpers::Translator.new("actions.setup_provisioner")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
# TODO prevent setup when no chef provisioner declared
|
16
|
+
# TODO catch ssh failure and report back on install issues
|
17
|
+
# TODO first check to see if it's installed and then skip the info
|
18
|
+
env[:ui].info @translator.t("install", :provisioner => "chef-solo")
|
19
|
+
env[:machine].communicate.execute(chef_install(env[:machine].guest))
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
def chef_install(guest)
|
25
|
+
read_script("chef", guest)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "vagrant-digitalocean/helpers/file"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Actions
|
6
|
+
class SetupSudo
|
7
|
+
include Helpers::File
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app, @env = app, env
|
11
|
+
@translator = Helpers::Translator.new("actions.setup_sudo")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:ui].info @translator.t("exec")
|
16
|
+
env[:machine].communicate.execute(fix_sudo(env[:machine].guest))
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
def fix_sudo(guest)
|
22
|
+
read_script("sudo", guest, false)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DigitalOcean
|
3
|
+
module Actions
|
4
|
+
class SetupUser
|
5
|
+
def initialize(app, env)
|
6
|
+
@app, @env = app, env
|
7
|
+
@translator = Helpers::Translator.new("actions.setup_user")
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
# create the user, set the password to username, add to sudoers
|
12
|
+
# NOTE assumes group with username is created with useradd
|
13
|
+
env[:ui].info @translator.t("create", :user => user)
|
14
|
+
env[:machine].communicate.execute(<<-BASH)
|
15
|
+
if ! (grep #{user} /etc/passwd); then
|
16
|
+
useradd -m -s /bin/bash #{user};
|
17
|
+
echo -e "#{user}\n#{user}" | (passwd #{user});
|
18
|
+
fi
|
19
|
+
BASH
|
20
|
+
|
21
|
+
env[:ui].info @translator.t("sudo", :user => user)
|
22
|
+
env[:machine].communicate.execute(<<-BASH)
|
23
|
+
if ! (grep #{user} /etc/sudoers); then
|
24
|
+
echo "#{user} ALL=(ALL:ALL) ALL" >> /etc/sudoers;
|
25
|
+
fi
|
26
|
+
BASH
|
27
|
+
|
28
|
+
# create the .ssh directory in the users home
|
29
|
+
env[:machine].communicate.execute("su #{user} -c 'mkdir -p ~/.ssh'")
|
30
|
+
|
31
|
+
env[:ui].info @translator.t("key")
|
32
|
+
# add the specified key to the authorized keys file
|
33
|
+
env[:machine].communicate.execute(<<-BASH)
|
34
|
+
if ! grep '#{pub_key}' /home/#{user}/.ssh/authorized_keys; then
|
35
|
+
echo '#{pub_key}' >> /home/#{user}/.ssh/authorized_keys;
|
36
|
+
fi
|
37
|
+
BASH
|
38
|
+
|
39
|
+
env[:machine_state] ||= {}
|
40
|
+
env[:machine_state][:user] = user
|
41
|
+
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# TODO use a config option to allow for alternate users
|
48
|
+
def user
|
49
|
+
"vagrant"
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO allow for a custom key to specified
|
53
|
+
def pub_key
|
54
|
+
@key ||= DigitalOcean.vagrant_key
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DigitalOcean
|
3
|
+
class Config < Vagrant.plugin("2", :config)
|
4
|
+
attr_accessor :client_id, :api_key, :image, :region, :size
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@client_id = UNSET_VALUE
|
8
|
+
@api_key = UNSET_VALUE
|
9
|
+
@image = UNSET_VALUE
|
10
|
+
@region = UNSET_VALUE
|
11
|
+
@size = UNSET_VALUE
|
12
|
+
end
|
13
|
+
|
14
|
+
def finalize!
|
15
|
+
@client_id = ENV["DO_CLIENT_ID"] if @client_id == UNSET_VALUE
|
16
|
+
@api_key = ENV["DO_API_KEY"] if @api_key == UNSET_VALUE
|
17
|
+
@image = "Ubuntu 12.04 x32 Server" if @image == UNSET_VALUE
|
18
|
+
@region = "New York 1" if @region == UNSET_VALUE
|
19
|
+
@size = "512MB" if @size == UNSET_VALUE
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate(machine)
|
23
|
+
errors = []
|
24
|
+
errors << "Client ID required" if !@client_id
|
25
|
+
errors << "API Key required" if !@api_key
|
26
|
+
|
27
|
+
{ "Digital Ocean Provider" => errors }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Errors
|
6
|
+
class DigitalOceanError < Vagrant::Errors::VagrantError
|
7
|
+
error_namespace("vagrant_digital_ocean.errors")
|
8
|
+
end
|
9
|
+
|
10
|
+
class APIStatusError < DigitalOceanError
|
11
|
+
error_key(:api_status)
|
12
|
+
end
|
13
|
+
|
14
|
+
class JSONError < DigitalOceanError
|
15
|
+
error_key(:json)
|
16
|
+
end
|
17
|
+
|
18
|
+
class ResultMatchError < DigitalOceanError
|
19
|
+
error_key(:result_match)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "vagrant-digitalocean/helpers/result"
|
2
|
+
require "faraday"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module DigitalOcean
|
7
|
+
module Helpers
|
8
|
+
class Client
|
9
|
+
def initialize
|
10
|
+
@client = Faraday.new(:url => "https://api.digitalocean.com/")
|
11
|
+
end
|
12
|
+
|
13
|
+
def request(path, params = {})
|
14
|
+
# create the key
|
15
|
+
result = @client.get(path, params = params.merge({
|
16
|
+
:client_id => ENV["DO_CLIENT_ID"],
|
17
|
+
:api_key => ENV["DO_API_KEY"]
|
18
|
+
}))
|
19
|
+
|
20
|
+
# remove the api key in case an error gets dumped to the console
|
21
|
+
params[:api_key] = "REMOVED"
|
22
|
+
|
23
|
+
begin
|
24
|
+
body = JSON.parse(result.body)
|
25
|
+
rescue JSON::ParserError => e
|
26
|
+
raise(Errors::JSONError, {
|
27
|
+
:message => e.message,
|
28
|
+
:path => path,
|
29
|
+
:params => params,
|
30
|
+
:response => result.body
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
if body["status"] != "OK"
|
35
|
+
raise(Errors::APIStatusError, {
|
36
|
+
:path => path,
|
37
|
+
:params => params,
|
38
|
+
:status => body["status"],
|
39
|
+
:response => body.inspect
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
43
|
+
Result.new(body)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
module Helpers
|
6
|
+
module File
|
7
|
+
# TODO the optional exceptions are clumsy
|
8
|
+
def read_file(relative_path, except = true)
|
9
|
+
content = ""
|
10
|
+
path = ::File.join(DigitalOcean.source_root, relative_path)
|
11
|
+
|
12
|
+
begin
|
13
|
+
::File.open(path) do |file|
|
14
|
+
content = file.read
|
15
|
+
end
|
16
|
+
rescue Errno::ENOENT => e
|
17
|
+
# ignore the missing file if except is false
|
18
|
+
raise(e) if except
|
19
|
+
end
|
20
|
+
|
21
|
+
content
|
22
|
+
end
|
23
|
+
|
24
|
+
# TODO the optional exceptions are clumsy
|
25
|
+
# read a script and match it to the guest operating system
|
26
|
+
def read_script(dir, guest, except = true)
|
27
|
+
script_dir = ::File.join("scripts", dir)
|
28
|
+
guest_name = guest.class.to_s
|
29
|
+
|
30
|
+
if guest_name =~ /Debian/ || guest_name =~ /Ubuntu/
|
31
|
+
read_file(::File.join(script_dir, "debian.sh"), except)
|
32
|
+
elsif guest_name =~ /RedHat/
|
33
|
+
read_file(::File.join(script_dir, "redhat.sh"), except)
|
34
|
+
else
|
35
|
+
raise "unsupported guest operating system" if except
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DigitalOcean
|
3
|
+
module Helpers
|
4
|
+
class Result
|
5
|
+
def initialize(body)
|
6
|
+
@result = body
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
@result[key.to_s]
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_id(sub_obj, search)
|
14
|
+
find(sub_obj, search)["id"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(sub_obj, search)
|
18
|
+
key = search.keys.first
|
19
|
+
value = search[key].to_s
|
20
|
+
key = key.to_s
|
21
|
+
|
22
|
+
result = @result[sub_obj.to_s].inject(nil) do |result, obj|
|
23
|
+
obj[key] == value ? obj : result
|
24
|
+
end
|
25
|
+
|
26
|
+
result || error(sub_obj, key, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def error(sub_obj, key, value)
|
30
|
+
raise(Errors::ResultMatchError, {
|
31
|
+
:key => key,
|
32
|
+
:value => value,
|
33
|
+
:collection_name => sub_obj.to_s,
|
34
|
+
:sub_obj => @result[sub_obj.to_s]
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DigitalOcean
|
3
|
+
module Helpers
|
4
|
+
class Translator
|
5
|
+
def self.plugin_namespace=(val)
|
6
|
+
@@plugin_namespace = val
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(namespace)
|
10
|
+
@namespace = namespace
|
11
|
+
end
|
12
|
+
|
13
|
+
def t(keys, opts = {})
|
14
|
+
value = I18n.t("#{@@plugin_namespace}.#{@namespace}.#{keys}", opts)
|
15
|
+
opts[:progress] == false ? value : value + " ..."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "i18n"
|
2
|
+
require "vagrant-digitalocean/helpers/translator"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module DigitalOcean
|
6
|
+
class Plugin < Vagrant.plugin("2")
|
7
|
+
name "DigitalOcean"
|
8
|
+
description <<-DESC
|
9
|
+
This plugin installs a provider that allows Vagrant to manage
|
10
|
+
machines using DigitalOcean's API.
|
11
|
+
DESC
|
12
|
+
|
13
|
+
config(:digital_ocean, :provider) do
|
14
|
+
require_relative "config"
|
15
|
+
Config
|
16
|
+
end
|
17
|
+
|
18
|
+
provider(:digital_ocean) do
|
19
|
+
# Return the provider
|
20
|
+
require_relative "provider"
|
21
|
+
|
22
|
+
I18n.load_path << File.expand_path("locales/en.yml", DigitalOcean.source_root)
|
23
|
+
I18n.reload!
|
24
|
+
Helpers::Translator.plugin_namespace = "vagrant_digital_ocean"
|
25
|
+
|
26
|
+
Provider
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "vagrant-digitalocean/action"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module DigitalOcean
|
5
|
+
class Provider < Vagrant.plugin("2", :provider)
|
6
|
+
# Initialize the provider to represent the given machine.
|
7
|
+
#
|
8
|
+
# @param [Vagrant::Machine] machine The machine that this provider
|
9
|
+
# is responsible for.
|
10
|
+
def initialize(machine)
|
11
|
+
@machine = machine
|
12
|
+
@dispatch = Action.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# This should return an action callable for the given name.
|
16
|
+
#
|
17
|
+
# @param [Symbol] name Name of the action.
|
18
|
+
# @return [Object] A callable action sequence object, whether it
|
19
|
+
# is a proc, object, etc.
|
20
|
+
def action(name)
|
21
|
+
return @dispatch.action(name) if @dispatch.respond_to?(name)
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# This method is called if the underying machine ID changes. Providers
|
26
|
+
# can use this method to load in new data for the actual backing
|
27
|
+
# machine or to realize that the machine is now gone (the ID can
|
28
|
+
# become `nil`). No parameters are given, since the underlying machine
|
29
|
+
# is simply the machine instance given to this object. And no
|
30
|
+
# return value is necessary.
|
31
|
+
def machine_id_changed
|
32
|
+
end
|
33
|
+
|
34
|
+
# This should return a hash of information that explains how to
|
35
|
+
# SSH into the machine. If the machine is not at a point where
|
36
|
+
# SSH is even possible, then `nil` should be returned.
|
37
|
+
#
|
38
|
+
# The general structure of this returned hash should be the
|
39
|
+
# following:
|
40
|
+
#
|
41
|
+
# {
|
42
|
+
# :host => "1.2.3.4",
|
43
|
+
# :port => "22",
|
44
|
+
# :username => "mitchellh",
|
45
|
+
# :private_key_path => "/path/to/my/key"
|
46
|
+
# }
|
47
|
+
#
|
48
|
+
# **Note:** Vagrant only supports private key based authenticatonion,
|
49
|
+
# mainly for the reason that there is no easy way to exec into an
|
50
|
+
# `ssh` prompt with a password, whereas we can pass a private key
|
51
|
+
# via commandline.
|
52
|
+
#
|
53
|
+
# @return [Hash] SSH information. For the structure of this hash
|
54
|
+
# read the accompanying documentation for this method.
|
55
|
+
def ssh_info
|
56
|
+
state = @machine.action("read_state")[:machine_state]
|
57
|
+
|
58
|
+
return nil if state["status"] == :not_created
|
59
|
+
|
60
|
+
return {
|
61
|
+
:host => state["ip_address"],
|
62
|
+
:port => "22",
|
63
|
+
:username => "root",
|
64
|
+
:private_key_path => Vagrant.source_root + "keys/vagrant"
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
# This should return the state of the machine within this provider.
|
69
|
+
# The state must be an instance of {MachineState}. Please read the
|
70
|
+
# documentation of that class for more information.
|
71
|
+
#
|
72
|
+
# @return [MachineState]
|
73
|
+
def state
|
74
|
+
state_id = @machine.action("read_state")[:machine_state]["status"].to_sym
|
75
|
+
|
76
|
+
# TODO provide an actual description
|
77
|
+
long = short = state_id.to_s
|
78
|
+
|
79
|
+
# Return the MachineState object
|
80
|
+
Vagrant::MachineState.new(state_id, short, long)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
require "vagrant-digitalocean/version"
|
3
|
+
require "vagrant-digitalocean/plugin"
|
4
|
+
require "vagrant-digitalocean/errors"
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module DigitalOcean
|
8
|
+
def self.source_root
|
9
|
+
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.vagrant_key
|
13
|
+
file = File.open(Vagrant.source_root + "keys/vagrant.pub")
|
14
|
+
key = file.read
|
15
|
+
file.close
|
16
|
+
key
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
en:
|
2
|
+
vagrant_digital_ocean:
|
3
|
+
errors:
|
4
|
+
api_status: |-
|
5
|
+
There was an issue with the request made to the Digital Ocean API at:
|
6
|
+
|
7
|
+
Path: %{path}
|
8
|
+
URI Params: %{params}
|
9
|
+
|
10
|
+
The response status from the API was:
|
11
|
+
|
12
|
+
Status: %{status}
|
13
|
+
Response: %{response}
|
14
|
+
:json: |-
|
15
|
+
There was an issue with the JSON response from the Digital Ocean API at:
|
16
|
+
|
17
|
+
Path: %{path}
|
18
|
+
URI Params: %{params}
|
19
|
+
|
20
|
+
The response JSON from the API was:
|
21
|
+
|
22
|
+
Response: %{response}
|
23
|
+
:result_match: |-
|
24
|
+
The result collection for %{collection_name}:
|
25
|
+
|
26
|
+
%{sub_obj}
|
27
|
+
|
28
|
+
Contained no object with the value "%{value}" for the the key "%{key}".
|
29
|
+
Please ensure that the configured value exists in the collection.
|
30
|
+
actions:
|
31
|
+
create:
|
32
|
+
skip: "Droplet is active, skipping creation"
|
33
|
+
create_key: "Adding key client account"
|
34
|
+
create_droplet: "Creating the droplet"
|
35
|
+
wait_active: "Waiting for the droplet to become active (>= 1 min)"
|
36
|
+
destroy:
|
37
|
+
destroying: "Destroying droplet"
|
38
|
+
not_active_or_new: "Droplet not in the `active` or `new` state"
|
39
|
+
clean_nfs: "Cleaning up NFS exports, may require sudo password"
|
40
|
+
wait_off: "Waiting for the droplet to be destroyed"
|
41
|
+
setup_sudo:
|
42
|
+
exec: "Making alterations to the sudoers file where necessary"
|
43
|
+
setup_nfs:
|
44
|
+
machine_ip: "Droplet IP: %{ip}"
|
45
|
+
host_ip: "Host IP: %{ip}"
|
46
|
+
install: "Installing NFS on the droplet"
|
47
|
+
force_shared_folders: "Forcing shared folders to use NFS where necessary"
|
48
|
+
setup_provisioner:
|
49
|
+
install: "Installing provisioner: %{provisioner} (>= 2 min)"
|
50
|
+
setup_user:
|
51
|
+
create: "Creating user '%{user}' and setting password"
|
52
|
+
sudo: "Enabling sudo for user '%{user}'"
|
53
|
+
key: "Adding public key to authorized_keys"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# cargo culted from OpsCode's guide at http://wiki.opscode.com/display/chef/Installing+Chef+Client+on+Ubuntu+or+Debian
|
2
|
+
# skip if the keys are present
|
3
|
+
if (which chef-solo); then exit 0; fi
|
4
|
+
|
5
|
+
# install the basics
|
6
|
+
apt-get install -y wget lsb-release;
|
7
|
+
|
8
|
+
# add the opscode repo to the sources
|
9
|
+
echo "deb http://apt.opscode.com/ `lsb_release -cs`-0.10 main" | sudo tee /etc/apt/sources.list.d/opscode.list;
|
10
|
+
|
11
|
+
# setup the gpg key
|
12
|
+
mkdir -p /etc/apt/trusted.gpg.d;
|
13
|
+
gpg --keyserver keys.gnupg.net --recv-keys 83EF826A;
|
14
|
+
gpg --export packages@opscode.com | sudo tee /etc/apt/trusted.gpg.d/opscode-keyring.gpg > /dev/null;
|
15
|
+
|
16
|
+
# update the repo to make sure that the package is available from the repo
|
17
|
+
apt-get update;
|
18
|
+
|
19
|
+
# avoid server url popup
|
20
|
+
echo "chef chef/chef_server_url string https://api.opscode.com/organizations/vagrant" | debconf-set-selections && apt-get install chef -y;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# cargo culted from OpsCode's guide at http://wiki.opscode.com/display/chef/Installing+Chef+Client+on+CentOS
|
2
|
+
# skip if chef-solo is present
|
3
|
+
if (which chef-solo); then exit 0; fi
|
4
|
+
|
5
|
+
# add the repo for ruby and other deps
|
6
|
+
rpm -Uvh http://rbel.frameos.org/rbel6
|
7
|
+
|
8
|
+
# install the pre-reqs
|
9
|
+
yum install -y ruby ruby-devel ruby-ri ruby-rdoc ruby-shadow gcc gcc-c++ automake autoconf make curl dmidecode
|
10
|
+
|
11
|
+
# install rubygems
|
12
|
+
if ! (which gem); then
|
13
|
+
cd /tmp
|
14
|
+
curl -O http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz
|
15
|
+
tar zxf rubygems-1.8.10.tgz
|
16
|
+
cd rubygems-1.8.10
|
17
|
+
ruby setup.rb --no-format-executable
|
18
|
+
fi
|
19
|
+
|
20
|
+
# install chef via rubygems
|
21
|
+
gem install chef --no-ri --no-rdoc
|
@@ -0,0 +1,11 @@
|
|
1
|
+
if (service --status-all | grep nfs); then exit 0; fi;
|
2
|
+
|
3
|
+
# install the nfs-kernel server
|
4
|
+
yum install -y nfs-utils nfs-utils-lib;
|
5
|
+
|
6
|
+
# add to startup
|
7
|
+
chkconfig nfs on;
|
8
|
+
|
9
|
+
# make sure it's on after the install
|
10
|
+
service rpcbind start;
|
11
|
+
service nfs start;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'vagrant-digitalocean/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "vagrant-digitalocean"
|
8
|
+
gem.version = VagrantPlugins::Digitalocean::VERSION
|
9
|
+
gem.authors = ["John Bender"]
|
10
|
+
gem.email = ["john.m.bender@gmail.com"]
|
11
|
+
gem.description = %q{Enables Vagrant to manage Digital Ocean droplets}
|
12
|
+
gem.summary = gem.description
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_dependency "faraday", "~> 0.8.6"
|
20
|
+
gem.add_dependency "json", "~> 1.6.6"
|
21
|
+
gem.add_dependency "log4r", "~> 1.1.9"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-digitalocean
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Bender
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: faraday
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.8.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.8.6
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.6.6
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.6.6
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: log4r
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.1.9
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.1.9
|
62
|
+
description: Enables Vagrant to manage Digital Ocean droplets
|
63
|
+
email:
|
64
|
+
- john.m.bender@gmail.com
|
65
|
+
executables:
|
66
|
+
- build.sh
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- bin/build.sh
|
76
|
+
- box/Vagrantfile
|
77
|
+
- box/digital_ocean.box
|
78
|
+
- box/metadata.json
|
79
|
+
- lib/vagrant-digitalocean.rb
|
80
|
+
- lib/vagrant-digitalocean/action.rb
|
81
|
+
- lib/vagrant-digitalocean/actions/create.rb
|
82
|
+
- lib/vagrant-digitalocean/actions/destroy.rb
|
83
|
+
- lib/vagrant-digitalocean/actions/read_state.rb
|
84
|
+
- lib/vagrant-digitalocean/actions/setup_nfs.rb
|
85
|
+
- lib/vagrant-digitalocean/actions/setup_provisioner.rb
|
86
|
+
- lib/vagrant-digitalocean/actions/setup_sudo.rb
|
87
|
+
- lib/vagrant-digitalocean/actions/setup_user.rb
|
88
|
+
- lib/vagrant-digitalocean/config.rb
|
89
|
+
- lib/vagrant-digitalocean/errors.rb
|
90
|
+
- lib/vagrant-digitalocean/helpers/client.rb
|
91
|
+
- lib/vagrant-digitalocean/helpers/file.rb
|
92
|
+
- lib/vagrant-digitalocean/helpers/result.rb
|
93
|
+
- lib/vagrant-digitalocean/helpers/translator.rb
|
94
|
+
- lib/vagrant-digitalocean/plugin.rb
|
95
|
+
- lib/vagrant-digitalocean/provider.rb
|
96
|
+
- lib/vagrant-digitalocean/version.rb
|
97
|
+
- locales/en.yml
|
98
|
+
- scripts/chef/debian.sh
|
99
|
+
- scripts/chef/redhat.sh
|
100
|
+
- scripts/nfs/debian.sh
|
101
|
+
- scripts/nfs/redhat.sh
|
102
|
+
- scripts/sudo/redhat.sh
|
103
|
+
- vagrant-digitalocean.gemspec
|
104
|
+
homepage:
|
105
|
+
licenses: []
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.8.23
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Enables Vagrant to manage Digital Ocean droplets
|
128
|
+
test_files: []
|