vagrant-openstack-provider 0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +22 -0
- data/RELEASE.md +15 -0
- data/Rakefile +21 -0
- data/Vagrantfile +37 -0
- data/dummy.box +0 -0
- data/example_box/README.md +13 -0
- data/example_box/metadata.json +3 -0
- data/features/provision.feature +35 -0
- data/features/steps/sdk_steps.rb +13 -0
- data/features/steps/server_steps.rb +25 -0
- data/features/support/env.rb +37 -0
- data/features/support/fog_mock.rb +19 -0
- data/features/vagrant-openstack.feature +70 -0
- data/gemfiles/latest_stable.gemfile +13 -0
- data/gemfiles/oldest_current.gemfile +13 -0
- data/gemfiles/previous_release.gemfile +13 -0
- data/lib/vagrant-openstack.rb +53 -0
- data/lib/vagrant-openstack/action.rb +123 -0
- data/lib/vagrant-openstack/action/connect_openstack.rb +30 -0
- data/lib/vagrant-openstack/action/create_server.rb +134 -0
- data/lib/vagrant-openstack/action/delete_server.rb +26 -0
- data/lib/vagrant-openstack/action/is_created.rb +16 -0
- data/lib/vagrant-openstack/action/message_already_created.rb +16 -0
- data/lib/vagrant-openstack/action/message_not_created.rb +16 -0
- data/lib/vagrant-openstack/action/read_ssh_info.rb +52 -0
- data/lib/vagrant-openstack/action/read_state.rb +40 -0
- data/lib/vagrant-openstack/action/sync_folders.rb +125 -0
- data/lib/vagrant-openstack/config.rb +229 -0
- data/lib/vagrant-openstack/errors.rb +36 -0
- data/lib/vagrant-openstack/openstack_client.rb +91 -0
- data/lib/vagrant-openstack/plugin.rb +37 -0
- data/lib/vagrant-openstack/provider.rb +50 -0
- data/lib/vagrant-openstack/version.rb +5 -0
- data/locales/en.yml +85 -0
- data/spec/vagrant-openstack/config_spec.rb +184 -0
- data/stackrc +32 -0
- data/vagrant-openstack.gemspec +23 -0
- metadata +135 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
require "vagrant/action/builder"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module Openstack
|
7
|
+
module Action
|
8
|
+
# Include the built-in modules so we can use them as top-level things.
|
9
|
+
include Vagrant::Action::Builtin
|
10
|
+
|
11
|
+
# This action is called to destroy the remote machine.
|
12
|
+
def self.action_destroy
|
13
|
+
Vagrant::Action::Builder.new.tap do |b|
|
14
|
+
b.use ConfigValidate
|
15
|
+
b.use Call, IsCreated do |env, b2|
|
16
|
+
if !env[:result]
|
17
|
+
b2.use MessageNotCreated
|
18
|
+
next
|
19
|
+
end
|
20
|
+
|
21
|
+
b2.use ConnectOpenstack
|
22
|
+
b2.use DeleteServer
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# This action is called when `vagrant provision` is called.
|
28
|
+
def self.action_provision
|
29
|
+
Vagrant::Action::Builder.new.tap do |b|
|
30
|
+
b.use ConfigValidate
|
31
|
+
b.use Call, IsCreated do |env, b2|
|
32
|
+
if !env[:result]
|
33
|
+
b2.use MessageNotCreated
|
34
|
+
next
|
35
|
+
end
|
36
|
+
|
37
|
+
b2.use Provision
|
38
|
+
b2.use SyncFolders
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# This action is called to read the SSH info of the machine. The
|
44
|
+
# resulting state is expected to be put into the `:machine_ssh_info`
|
45
|
+
# key.
|
46
|
+
def self.action_read_ssh_info
|
47
|
+
Vagrant::Action::Builder.new.tap do |b|
|
48
|
+
b.use ConfigValidate
|
49
|
+
b.use ConnectOpenstack
|
50
|
+
b.use ReadSSHInfo
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# This action is called to read the state of the machine. The
|
55
|
+
# resulting state is expected to be put into the `:machine_state_id`
|
56
|
+
# key.
|
57
|
+
def self.action_read_state
|
58
|
+
Vagrant::Action::Builder.new.tap do |b|
|
59
|
+
b.use ConfigValidate
|
60
|
+
b.use ConnectOpenstack
|
61
|
+
b.use ReadState
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.action_ssh
|
66
|
+
Vagrant::Action::Builder.new.tap do |b|
|
67
|
+
b.use ConfigValidate
|
68
|
+
b.use Call, IsCreated do |env, b2|
|
69
|
+
if !env[:result]
|
70
|
+
b2.use MessageNotCreated
|
71
|
+
next
|
72
|
+
end
|
73
|
+
|
74
|
+
b2.use SSHExec
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.action_ssh_run
|
80
|
+
Vagrant::Action::Builder.new.tap do |b|
|
81
|
+
b.use ConfigValidate
|
82
|
+
b.use Call, IsCreated do |env, b2|
|
83
|
+
if !env[:result]
|
84
|
+
b2.use MessageNotCreated
|
85
|
+
next
|
86
|
+
end
|
87
|
+
|
88
|
+
b2.use SSHRun
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.action_up
|
94
|
+
Vagrant::Action::Builder.new.tap do |b|
|
95
|
+
b.use ConfigValidate
|
96
|
+
b.use Call, IsCreated do |env, b2|
|
97
|
+
if env[:result]
|
98
|
+
b2.use MessageAlreadyCreated
|
99
|
+
next
|
100
|
+
end
|
101
|
+
|
102
|
+
b2.use ConnectOpenstack
|
103
|
+
b2.use Provision
|
104
|
+
b2.use SyncFolders
|
105
|
+
b2.use CreateServer
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# The autoload farm
|
111
|
+
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
112
|
+
autoload :ConnectOpenstack, action_root.join("connect_openstack")
|
113
|
+
autoload :CreateServer, action_root.join("create_server")
|
114
|
+
autoload :DeleteServer, action_root.join("delete_server")
|
115
|
+
autoload :IsCreated, action_root.join("is_created")
|
116
|
+
autoload :MessageAlreadyCreated, action_root.join("message_already_created")
|
117
|
+
autoload :MessageNotCreated, action_root.join("message_not_created")
|
118
|
+
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
|
119
|
+
autoload :ReadState, action_root.join("read_state")
|
120
|
+
autoload :SyncFolders, action_root.join("sync_folders")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "fog"
|
2
|
+
require "log4r"
|
3
|
+
require "restclient"
|
4
|
+
require "json"
|
5
|
+
require_relative "../openstack_client"
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Openstack
|
9
|
+
module Action
|
10
|
+
# This action connects to Openstack, verifies credentials work, and
|
11
|
+
# puts the Openstack connection object into the `:openstack_compute` key
|
12
|
+
# in the environment.
|
13
|
+
class ConnectOpenstack
|
14
|
+
def initialize(app, env)
|
15
|
+
@app = app
|
16
|
+
@logger = Log4r::Logger.new("vagrant_openstack::action::connect_openstack")
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
# Get the configs
|
21
|
+
config = env[:machine].provider_config
|
22
|
+
client = OpenstackClient::new()
|
23
|
+
env[:openstack_client] = client
|
24
|
+
client.authenticate(env)
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require "fog"
|
2
|
+
require "log4r"
|
3
|
+
require 'socket'
|
4
|
+
require "timeout"
|
5
|
+
|
6
|
+
require 'vagrant/util/retryable'
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module Openstack
|
10
|
+
module Action
|
11
|
+
class CreateServer
|
12
|
+
include Vagrant::Util::Retryable
|
13
|
+
|
14
|
+
def initialize(app, env)
|
15
|
+
@app = app
|
16
|
+
@logger = Log4r::Logger.new("vagrant_openstack::action::create_server")
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
config = env[:machine].provider_config
|
21
|
+
client = env[:openstack_client]
|
22
|
+
|
23
|
+
# Find the flavor
|
24
|
+
env[:ui].info(I18n.t("vagrant_openstack.finding_flavor"))
|
25
|
+
flavors = client.get_all_flavors(env)
|
26
|
+
flavor = find_matching(flavors, config.flavor)
|
27
|
+
raise Errors::NoMatchingFlavor if !flavor
|
28
|
+
|
29
|
+
# Find the image
|
30
|
+
env[:ui].info(I18n.t("vagrant_openstack.finding_image"))
|
31
|
+
images = client.get_all_images(env)
|
32
|
+
image = find_matching(images, config.image)
|
33
|
+
raise Errors::NoMatchingImage if !image
|
34
|
+
|
35
|
+
# Figure out the name for the server
|
36
|
+
server_name = config.server_name || env[:machine].name
|
37
|
+
|
38
|
+
# Output the settings we're going to use to the user
|
39
|
+
env[:ui].info(I18n.t("vagrant_openstack.launching_server"))
|
40
|
+
env[:ui].info(" -- Flavor : #{flavor.name}")
|
41
|
+
env[:ui].info(" -- FlavorRef : #{flavor.id}")
|
42
|
+
env[:ui].info(" -- Image : #{image.name}")
|
43
|
+
env[:ui].info(" -- KeyPair : #{config.keypair_name}")
|
44
|
+
env[:ui].info(" -- ImageRef : #{image.id}")
|
45
|
+
env[:ui].info(" -- Disk Config : #{config.disk_config}") if config.disk_config
|
46
|
+
env[:ui].info(" -- Network : #{config.network}") if config.network
|
47
|
+
env[:ui].info(" -- Tenant : #{config.tenant_name}")
|
48
|
+
env[:ui].info(" -- Name : #{server_name}")
|
49
|
+
|
50
|
+
#TODO(julienvey) add metadata
|
51
|
+
#TODO(julienvey) add availability_zone
|
52
|
+
#TODO(julienvey) add disk_config
|
53
|
+
|
54
|
+
server_id = client.create_server(env, server_name, image.id, flavor.id, config.keypair_name)
|
55
|
+
|
56
|
+
#TODO(julienvey) Find a network if provided
|
57
|
+
#if config.network
|
58
|
+
# network = find_matching(env[:openstack_network].networks, config.network)
|
59
|
+
# options[:nics] = [{"net_id" => network.id}] if network
|
60
|
+
#end
|
61
|
+
|
62
|
+
# Store the ID right away so we can track it
|
63
|
+
env[:machine].id = server_id
|
64
|
+
|
65
|
+
# Wait for the server to finish building
|
66
|
+
env[:ui].info(I18n.t("vagrant_openstack.waiting_for_build"))
|
67
|
+
timeout(200) do
|
68
|
+
while client.get_server_details(env, server_id)['status'] != 'ACTIVE' do
|
69
|
+
sleep 3
|
70
|
+
@logger.debug("Waiting for server to be ACTIVE")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if config.floating_ip
|
75
|
+
env[:ui].info("Using floating IP #{config.floating_ip}")
|
76
|
+
client.add_floating_ip(env, server_id, config.floating_ip)
|
77
|
+
end
|
78
|
+
|
79
|
+
if !env[:interrupted]
|
80
|
+
# Clear the line one more time so the progress is removed
|
81
|
+
env[:ui].clear_line
|
82
|
+
|
83
|
+
# Wait for SSH to become available
|
84
|
+
host = env[:machine].provider_config.floating_ip
|
85
|
+
ssh_timeout = env[:machine].provider_config.ssh_timeout
|
86
|
+
sleep 240
|
87
|
+
if !port_open?(env, host, 22, ssh_timeout)
|
88
|
+
env[:ui].error(I18n.t("vagrant_openstack.timeout"))
|
89
|
+
raise Errors::SshUnavailable,
|
90
|
+
:host => host,
|
91
|
+
:timeout => ssh_timeout
|
92
|
+
end
|
93
|
+
|
94
|
+
env[:ui].info(I18n.t("vagrant_openstack.ready"))
|
95
|
+
end
|
96
|
+
|
97
|
+
@app.call(env)
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
def port_open?(env, ip, port, timeout)
|
103
|
+
start_time = Time.now
|
104
|
+
current_time = start_time
|
105
|
+
while (current_time - start_time) <= timeout
|
106
|
+
begin
|
107
|
+
env[:ui].info(I18n.t("vagrant_openstack.waiting_for_ssh"))
|
108
|
+
TCPSocket.new(ip, port)
|
109
|
+
return true
|
110
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
111
|
+
sleep 1
|
112
|
+
end
|
113
|
+
current_time = Time.now
|
114
|
+
end
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
|
118
|
+
# This method finds a matching _thing_ in a collection of
|
119
|
+
# _things_. This works matching if the ID or NAME equals to
|
120
|
+
# `name`. Or, if `name` is a regexp, a partial match is chosen
|
121
|
+
# as well.
|
122
|
+
def find_matching(collection, name)
|
123
|
+
collection.each do |single|
|
124
|
+
return single if single.id == name
|
125
|
+
return single if single.name == name
|
126
|
+
return single if name.is_a?(Regexp) && name =~ single.name
|
127
|
+
end
|
128
|
+
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Openstack
|
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_openstack::action::delete_server")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if env[:machine].id
|
15
|
+
env[:ui].info(I18n.t("vagrant_openstack.deleting_server"))
|
16
|
+
server = env[:openstack_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 Openstack
|
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_openstack.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 Openstack
|
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_openstack.not_created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Openstack
|
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_openstack::action::read_ssh_info")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:machine_ssh_info] = read_ssh_info(env)
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_ssh_info(env)
|
21
|
+
client = env[:openstack_client]
|
22
|
+
machine = env[:machine]
|
23
|
+
config = env[:machine].provider_config
|
24
|
+
@logger.debug(config)
|
25
|
+
return nil if machine.id.nil?
|
26
|
+
begin
|
27
|
+
details = client.get_server_details(env, machine.id)
|
28
|
+
rescue Exception => e
|
29
|
+
# The machine can't be found
|
30
|
+
@logger.error(e)
|
31
|
+
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
32
|
+
machine.id = nil
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
|
36
|
+
for addr in details['addresses']['private']
|
37
|
+
if addr['OS-EXT-IPS:type'] == 'floating'
|
38
|
+
host = addr['addr']
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return {
|
43
|
+
# Usually there should only be one public IP
|
44
|
+
:host => host,
|
45
|
+
:port => 22,
|
46
|
+
:username => config.ssh_username
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Openstack
|
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_openstack::action::read_state")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:machine_state_id] = read_state(env)
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_state(env)
|
21
|
+
machine = env[:machine]
|
22
|
+
client = env[:openstack_client]
|
23
|
+
return :not_created if machine.id.nil?
|
24
|
+
|
25
|
+
# Find the machine
|
26
|
+
server = client.get_server_details(env, machine.id)
|
27
|
+
if server.nil? || server['status'] == "DELETED"
|
28
|
+
# The machine can't be found
|
29
|
+
@logger.info("Machine not found or deleted, assuming it got destroyed.")
|
30
|
+
machine.id = nil
|
31
|
+
return :not_created
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return the state
|
35
|
+
return server['status'].downcase.to_sym
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|