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.
Files changed (35) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +11 -0
  4. data/AUTHORS +5 -0
  5. data/Gemfile +11 -0
  6. data/LICENSE.txt +23 -0
  7. data/README.md +169 -0
  8. data/Rakefile +21 -0
  9. data/dummy.box +0 -0
  10. data/example_box/README.md +13 -0
  11. data/example_box/metadata.json +3 -0
  12. data/lib/vagrant-openstack-cloud-provider.rb +53 -0
  13. data/lib/vagrant-openstack-cloud-provider/action.rb +129 -0
  14. data/lib/vagrant-openstack-cloud-provider/action/connect_openstack.rb +34 -0
  15. data/lib/vagrant-openstack-cloud-provider/action/create_server.rb +185 -0
  16. data/lib/vagrant-openstack-cloud-provider/action/delete_server.rb +26 -0
  17. data/lib/vagrant-openstack-cloud-provider/action/is_created.rb +16 -0
  18. data/lib/vagrant-openstack-cloud-provider/action/message_already_created.rb +16 -0
  19. data/lib/vagrant-openstack-cloud-provider/action/message_not_created.rb +16 -0
  20. data/lib/vagrant-openstack-cloud-provider/action/read_ssh_info_from_api.rb +46 -0
  21. data/lib/vagrant-openstack-cloud-provider/action/read_ssh_info_from_cache.rb +53 -0
  22. data/lib/vagrant-openstack-cloud-provider/action/read_state.rb +38 -0
  23. data/lib/vagrant-openstack-cloud-provider/action/sync_folders.rb +58 -0
  24. data/lib/vagrant-openstack-cloud-provider/config.rb +126 -0
  25. data/lib/vagrant-openstack-cloud-provider/errors.rb +35 -0
  26. data/lib/vagrant-openstack-cloud-provider/plugin.rb +37 -0
  27. data/lib/vagrant-openstack-cloud-provider/provider.rb +50 -0
  28. data/lib/vagrant-openstack-cloud-provider/version.rb +5 -0
  29. data/locales/en.yml +81 -0
  30. data/spec/spec_helper.rb +21 -0
  31. data/spec/vagrant-openstack-cloud-provider/action/create_server_spec.rb +89 -0
  32. data/spec/vagrant-openstack-cloud-provider/action/read_ssh_info_spec.rb +122 -0
  33. data/spec/vagrant-openstack-cloud-provider/config_spec.rb +81 -0
  34. data/vagrant-openstack-cloud-provider.gemspec +25 -0
  35. 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
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module OpenStack
3
+ VERSION = "1.1.4"
4
+ end
5
+ 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.
@@ -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