vagrant-openstack-cloud-provider 1.1.4
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 +15 -0
- data/.gitignore +23 -0
- data/.travis.yml +11 -0
- data/AUTHORS +5 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +23 -0
- data/README.md +169 -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-openstack-cloud-provider.rb +53 -0
- data/lib/vagrant-openstack-cloud-provider/action.rb +129 -0
- data/lib/vagrant-openstack-cloud-provider/action/connect_openstack.rb +34 -0
- data/lib/vagrant-openstack-cloud-provider/action/create_server.rb +185 -0
- data/lib/vagrant-openstack-cloud-provider/action/delete_server.rb +26 -0
- data/lib/vagrant-openstack-cloud-provider/action/is_created.rb +16 -0
- data/lib/vagrant-openstack-cloud-provider/action/message_already_created.rb +16 -0
- data/lib/vagrant-openstack-cloud-provider/action/message_not_created.rb +16 -0
- data/lib/vagrant-openstack-cloud-provider/action/read_ssh_info_from_api.rb +46 -0
- data/lib/vagrant-openstack-cloud-provider/action/read_ssh_info_from_cache.rb +53 -0
- data/lib/vagrant-openstack-cloud-provider/action/read_state.rb +38 -0
- data/lib/vagrant-openstack-cloud-provider/action/sync_folders.rb +58 -0
- data/lib/vagrant-openstack-cloud-provider/config.rb +126 -0
- data/lib/vagrant-openstack-cloud-provider/errors.rb +35 -0
- data/lib/vagrant-openstack-cloud-provider/plugin.rb +37 -0
- data/lib/vagrant-openstack-cloud-provider/provider.rb +50 -0
- data/lib/vagrant-openstack-cloud-provider/version.rb +5 -0
- data/locales/en.yml +81 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/vagrant-openstack-cloud-provider/action/create_server_spec.rb +89 -0
- data/spec/vagrant-openstack-cloud-provider/action/read_ssh_info_spec.rb +122 -0
- data/spec/vagrant-openstack-cloud-provider/config_spec.rb +81 -0
- data/vagrant-openstack-cloud-provider.gemspec +25 -0
- metadata +123 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module OpenStack
|
5
|
+
class Config < Vagrant.plugin("2", :config)
|
6
|
+
# The API key to access OpenStack.
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :api_key
|
10
|
+
|
11
|
+
# The endpoint to access OpenStack.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :endpoint
|
15
|
+
|
16
|
+
# Openstack region, if your openstack instance uses these.
|
17
|
+
# Rackspace typically uses these. You need to provide their three letter acronym (for example: DFW)
|
18
|
+
# @return [String]
|
19
|
+
attr_accessor :region
|
20
|
+
|
21
|
+
# The flavor of server to launch, either the ID or name. This
|
22
|
+
# can also be a regular expression to partially match a name.
|
23
|
+
attr_accessor :flavor
|
24
|
+
|
25
|
+
# The name or ID of the image to use. This can also be a regular
|
26
|
+
# expression to partially match a name.
|
27
|
+
attr_accessor :image
|
28
|
+
|
29
|
+
# The name of the server. This defaults to the name of the machine
|
30
|
+
# defined by Vagrant (via `config.vm.define`), but can be overriden
|
31
|
+
# here.
|
32
|
+
attr_accessor :server_name
|
33
|
+
|
34
|
+
# The username to access OpenStack.
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
attr_accessor :username
|
38
|
+
|
39
|
+
# The name of the keypair to use.
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
attr_accessor :keypair_name
|
43
|
+
|
44
|
+
# The SSH username to use with this OpenStack instance. This overrides
|
45
|
+
# the `config.ssh.username` variable.
|
46
|
+
#
|
47
|
+
# @return [String]
|
48
|
+
attr_accessor :ssh_username
|
49
|
+
|
50
|
+
# User data to be sent to the newly created OpenStack instance. Use this
|
51
|
+
# e.g. to inject a script at boot time.
|
52
|
+
#
|
53
|
+
# @return [String]
|
54
|
+
attr_accessor :user_data
|
55
|
+
|
56
|
+
# Metadata to be sent to the newly created OpenStack instance.
|
57
|
+
#
|
58
|
+
# @return [Hash]
|
59
|
+
attr_accessor :metadata
|
60
|
+
|
61
|
+
# @return [String]
|
62
|
+
attr_accessor :public_network_name
|
63
|
+
|
64
|
+
# @return [String]
|
65
|
+
attr_accessor :networks
|
66
|
+
|
67
|
+
# @return [String]
|
68
|
+
attr_accessor :tenant
|
69
|
+
|
70
|
+
# @return [Hash]
|
71
|
+
attr_accessor :scheduler_hints
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@api_key = UNSET_VALUE
|
75
|
+
@endpoint = UNSET_VALUE
|
76
|
+
@region = UNSET_VALUE
|
77
|
+
@flavor = UNSET_VALUE
|
78
|
+
@image = UNSET_VALUE
|
79
|
+
@server_name = UNSET_VALUE
|
80
|
+
@username = UNSET_VALUE
|
81
|
+
@keypair_name = UNSET_VALUE
|
82
|
+
@ssh_username = UNSET_VALUE
|
83
|
+
@user_data = UNSET_VALUE
|
84
|
+
@metadata = UNSET_VALUE
|
85
|
+
@public_network_name = UNSET_VALUE
|
86
|
+
@networks = UNSET_VALUE
|
87
|
+
@tenant = UNSET_VALUE
|
88
|
+
@scheduler_hints = UNSET_VALUE
|
89
|
+
end
|
90
|
+
|
91
|
+
def finalize!
|
92
|
+
@api_key = nil if @api_key == UNSET_VALUE
|
93
|
+
@endpoint = nil if @endpoint == UNSET_VALUE
|
94
|
+
@region = nil if @region == UNSET_VALUE
|
95
|
+
@flavor = /m1.tiny/ if @flavor == UNSET_VALUE
|
96
|
+
@image = /cirros/ if @image == UNSET_VALUE
|
97
|
+
@server_name = nil if @server_name == UNSET_VALUE
|
98
|
+
@username = nil if @username == UNSET_VALUE
|
99
|
+
|
100
|
+
# Keypair defaults to nil
|
101
|
+
@keypair_name = nil if @keypair_name == UNSET_VALUE
|
102
|
+
|
103
|
+
# The SSH values by default are nil, and the top-level config
|
104
|
+
# `config.ssh` values are used.
|
105
|
+
@ssh_username = nil if @ssh_username == UNSET_VALUE
|
106
|
+
|
107
|
+
@user_data = "" if @user_data == UNSET_VALUE
|
108
|
+
@metadata = {} if @metadata == UNSET_VALUE
|
109
|
+
|
110
|
+
@public_network_name = "public" if @public_network_name == UNSET_VALUE
|
111
|
+
@networks = [@public_network_name] if @networks == UNSET_VALUE
|
112
|
+
@tenant = nil if @tenant == UNSET_VALUE
|
113
|
+
@scheduler_hints = {} if @scheduler_hints == UNSET_VALUE
|
114
|
+
end
|
115
|
+
|
116
|
+
def validate(machine)
|
117
|
+
errors = []
|
118
|
+
|
119
|
+
errors << I18n.t("vagrant_openstack.config.api_key_required") if !@api_key
|
120
|
+
errors << I18n.t("vagrant_openstack.config.username_required") if !@username
|
121
|
+
|
122
|
+
{ "OpenStack Provider" => errors }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module OpenStack
|
5
|
+
module Errors
|
6
|
+
class VagrantOpenStackError < Vagrant::Errors::VagrantError
|
7
|
+
error_namespace("vagrant_openstack.errors")
|
8
|
+
end
|
9
|
+
|
10
|
+
class CreateBadState < VagrantOpenStackError
|
11
|
+
error_key(:create_bad_state)
|
12
|
+
end
|
13
|
+
|
14
|
+
class SshUnavailable < VagrantOpenStackError
|
15
|
+
error_key(:ssh_unavailable)
|
16
|
+
end
|
17
|
+
|
18
|
+
class NoMatchingFlavor < VagrantOpenStackError
|
19
|
+
error_key(:no_matching_flavor)
|
20
|
+
end
|
21
|
+
|
22
|
+
class NoMatchingImage < VagrantOpenStackError
|
23
|
+
error_key(:no_matching_image)
|
24
|
+
end
|
25
|
+
|
26
|
+
class NoMatchingNetwork < VagrantOpenStackError
|
27
|
+
error_key(:no_matching_network)
|
28
|
+
end
|
29
|
+
|
30
|
+
class RsyncError < VagrantOpenStackError
|
31
|
+
error_key(:rsync_error)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
begin
|
2
|
+
require "vagrant"
|
3
|
+
rescue LoadError
|
4
|
+
raise "The OpenStack Cloud provider must be run within Vagrant."
|
5
|
+
end
|
6
|
+
|
7
|
+
# This is a sanity check to make sure no one is attempting to install
|
8
|
+
# this into an early Vagrant version.
|
9
|
+
if Vagrant::VERSION < "1.2.0"
|
10
|
+
raise "OpenStack Cloud provider is only compatible with Vagrant 1.2+"
|
11
|
+
end
|
12
|
+
|
13
|
+
module VagrantPlugins
|
14
|
+
module OpenStack
|
15
|
+
class Plugin < Vagrant.plugin("2")
|
16
|
+
name "OpenStack Cloud"
|
17
|
+
description <<-DESC
|
18
|
+
This plugin enables Vagrant to manage machines in OpenStack Cloud.
|
19
|
+
DESC
|
20
|
+
|
21
|
+
config(:openstack, :provider) do
|
22
|
+
require_relative "config"
|
23
|
+
Config
|
24
|
+
end
|
25
|
+
|
26
|
+
provider(:openstack, parallel: true) do
|
27
|
+
# Setup some things
|
28
|
+
OpenStack.init_i18n
|
29
|
+
OpenStack.init_logging
|
30
|
+
|
31
|
+
# Load the actual provider
|
32
|
+
require_relative "provider"
|
33
|
+
Provider
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
require "vagrant-openstack-cloud-provider/action"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module OpenStack
|
7
|
+
class Provider < Vagrant.plugin("2", :provider)
|
8
|
+
def initialize(machine)
|
9
|
+
@machine = machine
|
10
|
+
end
|
11
|
+
|
12
|
+
def action(name)
|
13
|
+
# Attempt to get the action method from the Action class if it
|
14
|
+
# exists, otherwise return nil to show that we don't support the
|
15
|
+
# given action.
|
16
|
+
action_method = "action_#{name}"
|
17
|
+
return Action.send(action_method) if Action.respond_to?(action_method)
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def ssh_info
|
22
|
+
# Run a custom action called "read_ssh_info" which does what it
|
23
|
+
# says and puts the resulting SSH info into the `:machine_ssh_info`
|
24
|
+
# key in the environment.
|
25
|
+
env = @machine.action("read_ssh_info")
|
26
|
+
env[:machine_ssh_info]
|
27
|
+
end
|
28
|
+
|
29
|
+
def state
|
30
|
+
# Run a custom action we define called "read_state" which does
|
31
|
+
# what it says. It puts the state in the `:machine_state_id`
|
32
|
+
# key in the environment.
|
33
|
+
env = @machine.action("read_state")
|
34
|
+
|
35
|
+
state_id = env[:machine_state_id]
|
36
|
+
|
37
|
+
# Get the short and long description
|
38
|
+
short = I18n.t("vagrant_openstack.states.short_#{state_id}")
|
39
|
+
long = I18n.t("vagrant_openstack.states.long_#{state_id}")
|
40
|
+
|
41
|
+
# Return the MachineState object
|
42
|
+
Vagrant::MachineState.new(state_id, short, long)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"OpenStack Cloud"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
en:
|
2
|
+
vagrant_openstack:
|
3
|
+
already_created: |-
|
4
|
+
The server is already created.
|
5
|
+
deleting_server: |-
|
6
|
+
Deleting server...
|
7
|
+
finding_flavor: |-
|
8
|
+
Finding flavor for server...
|
9
|
+
finding_image: |-
|
10
|
+
Finding image for server...
|
11
|
+
finding_network: |-
|
12
|
+
Finding network for server...
|
13
|
+
launching_server: |-
|
14
|
+
Launching a server with the following settings...
|
15
|
+
not_created: |-
|
16
|
+
The server hasn't been created yet. Run `vagrant up` first.
|
17
|
+
ready: |-
|
18
|
+
The server is ready!
|
19
|
+
rsync_folder: |-
|
20
|
+
Rsyncing folder: %{hostpath} => %{guestpath}
|
21
|
+
waiting_for_build: |-
|
22
|
+
Waiting for the server to be built...
|
23
|
+
waiting_for_ssh: |-
|
24
|
+
Waiting for SSH to become available...
|
25
|
+
|
26
|
+
config:
|
27
|
+
api_key_required: |-
|
28
|
+
An API key is required.
|
29
|
+
username_required: |-
|
30
|
+
A username is required.
|
31
|
+
|
32
|
+
errors:
|
33
|
+
create_bad_state: |-
|
34
|
+
While creating the server, it transitioned to an unexpected
|
35
|
+
state: '%{state}', instead of properly booting. Run `vagrant status`
|
36
|
+
to find out what can be done about this state, or `vagrant destroy`
|
37
|
+
if you want to start over.
|
38
|
+
ssh_unavailable: |-
|
39
|
+
The server has been created successfully but it refuses incomming
|
40
|
+
ssh connections.
|
41
|
+
no_matching_flavor: |-
|
42
|
+
No matching flavor was found! Please check your flavor setting
|
43
|
+
to make sure you have a valid flavor chosen.
|
44
|
+
no_matching_image: |-
|
45
|
+
No matching image was found! Please check your image setting to
|
46
|
+
make sure you have a valid image chosen.
|
47
|
+
no_matching_network: |-
|
48
|
+
No network was found for name "%{network_name}". Please check your
|
49
|
+
network setting to make sure you have a valid network chosen.
|
50
|
+
rsync_error: |-
|
51
|
+
There was an error when attemping to rsync a share folder.
|
52
|
+
Please inspect the error message below for more info.
|
53
|
+
|
54
|
+
Host path: %{hostpath}
|
55
|
+
Guest path: %{guestpath}
|
56
|
+
Error: %{stderr}
|
57
|
+
|
58
|
+
states:
|
59
|
+
short_active: |-
|
60
|
+
active
|
61
|
+
long_active: |-
|
62
|
+
The server is up and running. Run `vagrant ssh` to access it.
|
63
|
+
short_build: |-
|
64
|
+
building
|
65
|
+
long_build: |-
|
66
|
+
The server is currently being built. You must wait for this to
|
67
|
+
complete before you can access it. You can delete the server, however,
|
68
|
+
by running `vagrant destroy`.
|
69
|
+
short_shutoff: |-
|
70
|
+
shutoff
|
71
|
+
long_shutoff: |-
|
72
|
+
The server is shutoff.
|
73
|
+
short_error: |-
|
74
|
+
error
|
75
|
+
long_error: |-
|
76
|
+
The server is in an erroneous state. Destroy the machine with
|
77
|
+
`vagrant destroy`.
|
78
|
+
short_not_created: |-
|
79
|
+
not created
|
80
|
+
long_not_created: |-
|
81
|
+
The server is not created. Run `vagrant up` to create it.
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative '../lib/vagrant-openstack-cloud-provider/errors'
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start
|
4
|
+
|
5
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
6
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
7
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
8
|
+
# loaded once.
|
9
|
+
#
|
10
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
config.filter_run :focus
|
15
|
+
|
16
|
+
# Run specs in random order to surface order dependencies. If you find an
|
17
|
+
# order dependency and want to debug it, you can fix the order by providing
|
18
|
+
# the seed, which is printed after each run.
|
19
|
+
# --seed 1234
|
20
|
+
config.order = 'random'
|
21
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'vagrant-openstack-cloud-provider/errors'
|
3
|
+
require 'vagrant-openstack-cloud-provider/action/create_server'
|
4
|
+
|
5
|
+
describe VagrantPlugins::OpenStack::Action::CreateServer do
|
6
|
+
describe '#server_to_be_available?' do
|
7
|
+
subject {
|
8
|
+
described_class.new(nil, nil)
|
9
|
+
}
|
10
|
+
|
11
|
+
let(:server) { double }
|
12
|
+
|
13
|
+
it "returns true when server is active" do
|
14
|
+
server.stub(:state).and_return('ACTIVE')
|
15
|
+
subject.server_to_be_available?(server).should == true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise when the server state is ERROR" do
|
19
|
+
server.stub(:state).and_return('ERROR')
|
20
|
+
expect { subject.server_to_be_available?(server) }.to raise_error(RuntimeError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#ssh_responding?' do
|
25
|
+
subject {
|
26
|
+
described_class.new(nil, nil)
|
27
|
+
}
|
28
|
+
|
29
|
+
let(:ui) { double }
|
30
|
+
let(:machine) { double }
|
31
|
+
let(:communicate) { double }
|
32
|
+
|
33
|
+
it "should continue if ssh is available" do
|
34
|
+
ui.stub(:info)
|
35
|
+
communicate.stub(:ready?).and_return(true)
|
36
|
+
machine.stub(:communicate).and_return(communicate)
|
37
|
+
env = { :ui => ui, :interrupted => false, :machine => machine }
|
38
|
+
subject.send('ssh_responding?', env)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise if ssh isn't available" do
|
42
|
+
ui.stub(:info)
|
43
|
+
communicate.stub(:ready?).and_return(false)
|
44
|
+
machine.stub(:communicate).and_return(communicate)
|
45
|
+
env = { :ui => ui, :interrupted => false, :machine => machine }
|
46
|
+
expect { subject.send('ssh_responding?', env) }.to raise_error(VagrantPlugins::OpenStack::Errors::SshUnavailable)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#find_matching' do
|
51
|
+
subject {
|
52
|
+
described_class.new(nil, nil)
|
53
|
+
}
|
54
|
+
|
55
|
+
it "returns a match for a list of hashes" do
|
56
|
+
haystack = [{"status"=>"ACTIVE", "subnets"=>["d8908f8c-07f4-405b-bbab-e19c768f293f"], "name"=>"solidfire", "provider:physical_network"=>"physnet1", "admin_state_up"=>true, "tenant_id"=>"2c9fba23721f4126ab244020e641f5f5", "provider:network_type"=>"vlan", "router:external"=>false, "shared"=>true, "id"=>"192702e6-3444-4162-b244-3af8b50fbb45", "provider:segmentation_id"=>3999}, {"status"=>"ACTIVE", "subnets"=>["d4318e28-5acd-415f-b300-0502f33b0dea"], "name"=>"public", "provider:physical_network"=>"physnet0", "admin_state_up"=>true, "tenant_id"=>"2c9fba23721f4126ab244020e641f5f5", "provider:network_type"=>"vlan", "router:external"=>false, "shared"=>true, "id"=>"e44bf8cb-7326-4abc-b96d-5404d5ed7767", "provider:segmentation_id"=>2753}]
|
57
|
+
needle = {"status"=>"ACTIVE", "subnets"=>["d4318e28-5acd-415f-b300-0502f33b0dea"], "name"=>"public", "provider:physical_network"=>"physnet0", "admin_state_up"=>true, "tenant_id"=>"2c9fba23721f4126ab244020e641f5f5", "provider:network_type"=>"vlan", "router:external"=>false, "shared"=>true, "id"=>"e44bf8cb-7326-4abc-b96d-5404d5ed7767", "provider:segmentation_id"=>2753}
|
58
|
+
|
59
|
+
subject.send('find_matching', haystack, needle['name']).should == needle
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns a match for a list of objects with matching id" do
|
63
|
+
object1 = double()
|
64
|
+
object1.stub('id' => 'matching_value')
|
65
|
+
object1.stub('name' => 'not_this')
|
66
|
+
|
67
|
+
haystack = [object1]
|
68
|
+
subject.send('find_matching', haystack, 'matching_value').should == object1
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns a match for a list of objects with matching name" do
|
72
|
+
object1 = double()
|
73
|
+
object1.stub('id' => 'not_this')
|
74
|
+
object1.stub('name' => 'matching_value')
|
75
|
+
|
76
|
+
haystack = [object1]
|
77
|
+
subject.send('find_matching', haystack, 'matching_value').should == object1
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns a match for a list of objects with a matching regexp" do
|
81
|
+
object1 = double()
|
82
|
+
object1.stub('id' => 'not_this')
|
83
|
+
object1.stub('name' => '2020 des fin fin')
|
84
|
+
|
85
|
+
haystack = [object1]
|
86
|
+
subject.send('find_matching', haystack, /des fin/).should == object1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|