vagrant-rackspace 0.1.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 +3 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +21 -0
- data/dummy.box +0 -0
- data/example_box/README.md +13 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-rackspace.rb +53 -0
- data/lib/vagrant-rackspace/action.rb +95 -0
- data/lib/vagrant-rackspace/action/connect_rackspace.rb +37 -0
- data/lib/vagrant-rackspace/action/create_server.rb +126 -0
- data/lib/vagrant-rackspace/action/delete_server.rb +26 -0
- data/lib/vagrant-rackspace/action/is_created.rb +16 -0
- data/lib/vagrant-rackspace/action/message_already_created.rb +16 -0
- data/lib/vagrant-rackspace/action/message_not_created.rb +16 -0
- data/lib/vagrant-rackspace/action/read_ssh_info.rb +42 -0
- data/lib/vagrant-rackspace/action/read_state.rb +38 -0
- data/lib/vagrant-rackspace/action/sync_folders.rb +57 -0
- data/lib/vagrant-rackspace/action/warn_networks.rb +19 -0
- data/lib/vagrant-rackspace/config.rb +79 -0
- data/lib/vagrant-rackspace/errors.rb +27 -0
- data/lib/vagrant-rackspace/plugin.rb +37 -0
- data/lib/vagrant-rackspace/provider.rb +50 -0
- data/lib/vagrant-rackspace/version.rb +5 -0
- data/locales/en.yml +82 -0
- data/spec/vagrant-rackspace/config_spec.rb +65 -0
- data/vagrant-rackspace.gemspec +24 -0
- metadata +129 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
require "fog"
|
2
|
+
require "log4r"
|
3
|
+
|
4
|
+
require 'vagrant/util/retryable'
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module Rackspace
|
8
|
+
module Action
|
9
|
+
# This creates the Rackspace server.
|
10
|
+
class CreateServer
|
11
|
+
include Vagrant::Util::Retryable
|
12
|
+
|
13
|
+
def initialize(app, env)
|
14
|
+
@app = app
|
15
|
+
@logger = Log4r::Logger.new("vagrant_rackspace::action::create_server")
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
# Get the configs
|
20
|
+
config = env[:machine].provider_config
|
21
|
+
|
22
|
+
# Find the flavor
|
23
|
+
env[:ui].info(I18n.t("vagrant_rackspace.finding_flavor"))
|
24
|
+
flavor = find_matching(env[:rackspace_compute].flavors.all, config.flavor)
|
25
|
+
raise Errors::NoMatchingFlavor if !flavor
|
26
|
+
|
27
|
+
# Find the image
|
28
|
+
env[:ui].info(I18n.t("vagrant_rackspace.finding_image"))
|
29
|
+
image = find_matching(env[:rackspace_compute].images.all, config.image)
|
30
|
+
raise Errors::NoMatchingImage if !image
|
31
|
+
|
32
|
+
# Figure out the name for the server
|
33
|
+
server_name = config.server_name || env[:machine].name
|
34
|
+
|
35
|
+
# If we're using the default keypair, then show a warning
|
36
|
+
default_key_path = Vagrant.source_root.join("keys/vagrant.pub").to_s
|
37
|
+
public_key_path = File.expand_path(config.public_key_path, env[:root_path])
|
38
|
+
|
39
|
+
if default_key_path == public_key_path
|
40
|
+
env[:ui].warn(I18n.t("vagrant_rackspace.warn_insecure_ssh"))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Output the settings we're going to use to the user
|
44
|
+
env[:ui].info(I18n.t("vagrant_rackspace.launching_server"))
|
45
|
+
env[:ui].info(" -- Flavor: #{flavor.name}")
|
46
|
+
env[:ui].info(" -- Image: #{image.name}")
|
47
|
+
env[:ui].info(" -- Name: #{server_name}")
|
48
|
+
|
49
|
+
# Build the options for launching...
|
50
|
+
options = {
|
51
|
+
:flavor_id => flavor.id,
|
52
|
+
:image_id => image.id,
|
53
|
+
:name => server_name,
|
54
|
+
:personality => [
|
55
|
+
{
|
56
|
+
:path => "/root/.ssh/authorized_keys",
|
57
|
+
:contents => Base64.encode64(File.read(public_key_path))
|
58
|
+
}
|
59
|
+
]
|
60
|
+
}
|
61
|
+
|
62
|
+
# Create the server
|
63
|
+
server = env[:rackspace_compute].servers.create(options)
|
64
|
+
|
65
|
+
# Store the ID right away so we can track it
|
66
|
+
env[:machine].id = server.id
|
67
|
+
|
68
|
+
# Wait for the server to finish building
|
69
|
+
env[:ui].info(I18n.t("vagrant_rackspace.waiting_for_build"))
|
70
|
+
retryable(:on => Fog::Errors::TimeoutError, :tries => 200) do
|
71
|
+
# If we're interrupted don't worry about waiting
|
72
|
+
next if env[:interrupted]
|
73
|
+
|
74
|
+
# Set the progress
|
75
|
+
env[:ui].clear_line
|
76
|
+
env[:ui].report_progress(server.progress, 100, false)
|
77
|
+
|
78
|
+
# Wait for the server to be ready
|
79
|
+
begin
|
80
|
+
server.wait_for(5) { ready? }
|
81
|
+
rescue RuntimeError => e
|
82
|
+
# If we don't have an error about a state transition, then
|
83
|
+
# we just move on.
|
84
|
+
raise if e.message !~ /should have transitioned/
|
85
|
+
raise Errors::CreateBadState, :state => server.state
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if !env[:interrupted]
|
90
|
+
# Clear the line one more time so the progress is removed
|
91
|
+
env[:ui].clear_line
|
92
|
+
|
93
|
+
# Wait for SSH to become available
|
94
|
+
env[:ui].info(I18n.t("vagrant_rackspace.waiting_for_ssh"))
|
95
|
+
while true
|
96
|
+
# If we're interrupted then just back out
|
97
|
+
break if env[:interrupted]
|
98
|
+
break if env[:machine].communicate.ready?
|
99
|
+
sleep 2
|
100
|
+
end
|
101
|
+
|
102
|
+
env[:ui].info(I18n.t("vagrant_rackspace.ready"))
|
103
|
+
end
|
104
|
+
|
105
|
+
@app.call(env)
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
|
110
|
+
# This method finds a matching _thing_ in a collection of
|
111
|
+
# _things_. This works matching if the ID or NAME equals to
|
112
|
+
# `name`. Or, if `name` is a regexp, a partial match is chosen
|
113
|
+
# as well.
|
114
|
+
def find_matching(collection, name)
|
115
|
+
collection.each do |single|
|
116
|
+
return single if single.id == name
|
117
|
+
return single if single.name == name
|
118
|
+
return single if name.is_a?(Regexp) && name =~ single.name
|
119
|
+
end
|
120
|
+
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Rackspace
|
5
|
+
module Action
|
6
|
+
# This deletes the running server, if there is one.
|
7
|
+
class DeleteServer
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_rackspace::action::delete_server")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if env[:machine].id
|
15
|
+
env[:ui].info(I18n.t("vagrant_rackspace.deleting_server"))
|
16
|
+
server = env[:rackspace_compute].servers.get(env[:machine].id)
|
17
|
+
server.destroy
|
18
|
+
env[:machine].id = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Rackspace
|
3
|
+
module Action
|
4
|
+
class MessageAlreadyCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_rackspace.already_created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Rackspace
|
3
|
+
module Action
|
4
|
+
class MessageNotCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_rackspace.not_created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Rackspace
|
5
|
+
module Action
|
6
|
+
# This action reads the SSH info for the machine and puts it into the
|
7
|
+
# `:machine_ssh_info` key in the environment.
|
8
|
+
class ReadSSHInfo
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant_rackspace::action::read_ssh_info")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:machine_ssh_info] = read_ssh_info(env[:rackspace_compute], env[:machine])
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_ssh_info(rackspace, machine)
|
21
|
+
return nil if machine.id.nil?
|
22
|
+
|
23
|
+
# Find the machine
|
24
|
+
server = rackspace.servers.get(machine.id)
|
25
|
+
if server.nil?
|
26
|
+
# The machine can't be found
|
27
|
+
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
28
|
+
machine.id = nil
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Read the DNS info
|
33
|
+
return {
|
34
|
+
:host => server.ipv4_address,
|
35
|
+
:port => 22,
|
36
|
+
:username => "root"
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Rackspace
|
5
|
+
module Action
|
6
|
+
# This action reads the state of the machine and puts it in the
|
7
|
+
# `:machine_state_id` key in the environment.
|
8
|
+
class ReadState
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant_rackspace::action::read_state")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:machine_state_id] = read_state(env[:rackspace_compute], env[:machine])
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_state(rackspace, machine)
|
21
|
+
return :not_created if machine.id.nil?
|
22
|
+
|
23
|
+
# Find the machine
|
24
|
+
server = rackspace.servers.get(machine.id)
|
25
|
+
if server.nil? || server.state == "DELETED"
|
26
|
+
# The machine can't be found
|
27
|
+
@logger.info("Machine not found or deleted, assuming it got destroyed.")
|
28
|
+
machine.id = nil
|
29
|
+
return :not_created
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return the state
|
33
|
+
return server.state.downcase.to_sym
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
require "vagrant/util/subprocess"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module Rackspace
|
7
|
+
module Action
|
8
|
+
# This middleware uses `rsync` to sync the folders over to the
|
9
|
+
# remote instance.
|
10
|
+
class SyncFolders
|
11
|
+
def initialize(app, env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new("vagrant_rackspace::action::sync_folders")
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
@app.call(env)
|
18
|
+
|
19
|
+
ssh_info = env[:machine].ssh_info
|
20
|
+
|
21
|
+
env[:machine].config.vm.synced_folders.each do |id, data|
|
22
|
+
hostpath = File.expand_path(data[:hostpath], env[:root_path])
|
23
|
+
guestpath = data[:guestpath]
|
24
|
+
|
25
|
+
# Make sure there is a trailing slash on the host path to
|
26
|
+
# avoid creating an additional directory with rsync
|
27
|
+
hostpath = "#{hostpath}/" if hostpath !~ /\/$/
|
28
|
+
|
29
|
+
env[:ui].info(I18n.t("vagrant_rackspace.rsync_folder",
|
30
|
+
:hostpath => hostpath,
|
31
|
+
:guestpath => guestpath))
|
32
|
+
|
33
|
+
# Create the guest path
|
34
|
+
env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
|
35
|
+
env[:machine].communicate.sudo(
|
36
|
+
"chown #{ssh_info[:username]} '#{guestpath}'")
|
37
|
+
|
38
|
+
# Rsync over to the guest path using the SSH info
|
39
|
+
command = [
|
40
|
+
"rsync", "--verbose", "--archive", "-z",
|
41
|
+
"-e", "ssh -p #{ssh_info[:port]} -i '#{ssh_info[:private_key_path]}'",
|
42
|
+
hostpath,
|
43
|
+
"#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
|
44
|
+
|
45
|
+
r = Vagrant::Util::Subprocess.execute(*command)
|
46
|
+
if r.exit_code != 0
|
47
|
+
raise Errors::RsyncError,
|
48
|
+
:guestpath => guestpath,
|
49
|
+
:hostpath => hostpath,
|
50
|
+
:stderr => r.stderr
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Rackspace
|
3
|
+
module Action
|
4
|
+
class WarnNetworks
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
if env[:machine].config.vm.networks.length > 0
|
11
|
+
env[:ui].warn(I18n.t("vagrant_rackspace.warn_networks"))
|
12
|
+
end
|
13
|
+
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Rackspace
|
5
|
+
class Config < Vagrant.plugin("2", :config)
|
6
|
+
# The API key to access RackSpace.
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :api_key
|
10
|
+
|
11
|
+
# The endpoint to access RackSpace. If nil, it will default
|
12
|
+
# to DFW.
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
attr_accessor :endpoint
|
16
|
+
|
17
|
+
# The flavor of server to launch, either the ID or name. This
|
18
|
+
# can also be a regular expression to partially match a name.
|
19
|
+
attr_accessor :flavor
|
20
|
+
|
21
|
+
# The name or ID of the image to use. This can also be a regular
|
22
|
+
# expression to partially match a name.
|
23
|
+
attr_accessor :image
|
24
|
+
|
25
|
+
# The path to the public key to set up on the remote server for SSH.
|
26
|
+
# This should match the private key configured with `config.ssh.private_key_path`.
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
attr_accessor :public_key_path
|
30
|
+
|
31
|
+
# The name of the server. This defaults to the name of the machine
|
32
|
+
# defined by Vagrant (via `config.vm.define`), but can be overriden
|
33
|
+
# here.
|
34
|
+
attr_accessor :server_name
|
35
|
+
|
36
|
+
# The username to access RackSpace.
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
attr_accessor :username
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@api_key = UNSET_VALUE
|
43
|
+
@endpoint = UNSET_VALUE
|
44
|
+
@flavor = UNSET_VALUE
|
45
|
+
@image = UNSET_VALUE
|
46
|
+
@public_key_path = UNSET_VALUE
|
47
|
+
@server_name = UNSET_VALUE
|
48
|
+
@username = UNSET_VALUE
|
49
|
+
end
|
50
|
+
|
51
|
+
def finalize!
|
52
|
+
@api_key = nil if @api_key == UNSET_VALUE
|
53
|
+
@endpoint = nil if @endpoint == UNSET_VALUE
|
54
|
+
@flavor = /512MB/ if @flavor == UNSET_VALUE
|
55
|
+
@image = /Ubuntu/ if @image == UNSET_VALUE
|
56
|
+
@server_name = nil if @server_name == UNSET_VALUE
|
57
|
+
@username = nil if @username == UNSET_VALUE
|
58
|
+
|
59
|
+
if @public_key_path == UNSET_VALUE
|
60
|
+
@public_key_path = Vagrant.source_root.join("keys/vagrant.pub")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate(machine)
|
65
|
+
errors = []
|
66
|
+
|
67
|
+
errors << I18n.t("vagrant_rackspace.config.api_key_required") if !@api_key
|
68
|
+
errors << I18n.t("vagrant_rackspace.config.username_required") if !@username
|
69
|
+
|
70
|
+
public_key_path = File.expand_path(@public_key_path, machine.env.root_path)
|
71
|
+
if !File.file?(public_key_path)
|
72
|
+
errors << I18n.t("vagrant_rackspace.config.public_key_not_found")
|
73
|
+
end
|
74
|
+
|
75
|
+
{ "RackSpace Provider" => errors }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|