vagrant-openstack-provider 0.4.1 → 0.5.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -2
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile +8 -15
  5. data/Vagrantfile +12 -10
  6. data/gemfiles/latest_stable.gemfile +6 -16
  7. data/gemfiles/minimal_release.gemfile +10 -0
  8. data/gemfiles/previous_release.gemfile +6 -16
  9. data/lib/vagrant-openstack-provider/action/connect_openstack.rb +2 -1
  10. data/lib/vagrant-openstack-provider/action/create_server.rb +40 -248
  11. data/lib/vagrant-openstack-provider/action/read_ssh_info.rb +30 -29
  12. data/lib/vagrant-openstack-provider/action/sync_folders.rb +19 -9
  13. data/lib/vagrant-openstack-provider/action/wait_accessible.rb +58 -0
  14. data/lib/vagrant-openstack-provider/action/wait_active.rb +5 -3
  15. data/lib/vagrant-openstack-provider/action/wait_stop.rb +5 -3
  16. data/lib/vagrant-openstack-provider/action.rb +19 -11
  17. data/lib/vagrant-openstack-provider/client/http_utils.rb +3 -2
  18. data/lib/vagrant-openstack-provider/client/neutron.rb +11 -1
  19. data/lib/vagrant-openstack-provider/client/nova.rb +49 -30
  20. data/lib/vagrant-openstack-provider/command/abstract_command.rb +10 -1
  21. data/lib/vagrant-openstack-provider/command/flavor_list.rb +1 -1
  22. data/lib/vagrant-openstack-provider/command/floatingip_list.rb +1 -1
  23. data/lib/vagrant-openstack-provider/command/image_list.rb +1 -1
  24. data/lib/vagrant-openstack-provider/command/main.rb +2 -1
  25. data/lib/vagrant-openstack-provider/command/network_list.rb +8 -2
  26. data/lib/vagrant-openstack-provider/command/reset.rb +21 -0
  27. data/lib/vagrant-openstack-provider/command/utils.rb +1 -1
  28. data/lib/vagrant-openstack-provider/command/volume_list.rb +1 -1
  29. data/lib/vagrant-openstack-provider/config.rb +16 -1
  30. data/lib/vagrant-openstack-provider/config_resolver.rb +262 -0
  31. data/lib/vagrant-openstack-provider/errors.rb +40 -0
  32. data/lib/vagrant-openstack-provider/plugin.rb +3 -3
  33. data/lib/vagrant-openstack-provider/utils.rb +21 -0
  34. data/lib/vagrant-openstack-provider/version.rb +1 -1
  35. data/locales/en.yml +35 -1
  36. data/spec/vagrant-openstack-provider/action/create_server_spec.rb +121 -368
  37. data/spec/vagrant-openstack-provider/action/delete_server_spec.rb +54 -0
  38. data/spec/vagrant-openstack-provider/action/message_spec.rb +34 -0
  39. data/spec/vagrant-openstack-provider/action/read_ssh_info_spec.rb +34 -17
  40. data/spec/vagrant-openstack-provider/action/read_state_spec.rb +70 -0
  41. data/spec/vagrant-openstack-provider/action/resume_server_spec.rb +50 -0
  42. data/spec/vagrant-openstack-provider/action/start_server_spec.rb +50 -0
  43. data/spec/vagrant-openstack-provider/action/stop_server_spec.rb +50 -0
  44. data/spec/vagrant-openstack-provider/action/suspend_server_spec.rb +50 -0
  45. data/spec/vagrant-openstack-provider/action/sync_folders_spec.rb +155 -0
  46. data/spec/vagrant-openstack-provider/action/wait_accessible_spec.rb +68 -0
  47. data/spec/vagrant-openstack-provider/action/wait_active_spec.rb +47 -0
  48. data/spec/vagrant-openstack-provider/action/wait_stop_spec.rb +47 -0
  49. data/spec/vagrant-openstack-provider/action_spec.rb +121 -0
  50. data/spec/vagrant-openstack-provider/client/cinder_spec.rb +1 -1
  51. data/spec/vagrant-openstack-provider/client/keystone_spec.rb +1 -1
  52. data/spec/vagrant-openstack-provider/client/neutron_spec.rb +37 -1
  53. data/spec/vagrant-openstack-provider/client/nova_spec.rb +60 -7
  54. data/spec/vagrant-openstack-provider/client/utils_spec.rb +1 -1
  55. data/spec/vagrant-openstack-provider/command/flavor_list_spec.rb +44 -0
  56. data/spec/vagrant-openstack-provider/command/floatingip_list_spec.rb +19 -2
  57. data/spec/vagrant-openstack-provider/command/image_list_spec.rb +48 -0
  58. data/spec/vagrant-openstack-provider/command/network_list_spec.rb +67 -0
  59. data/spec/vagrant-openstack-provider/command/reset_spec.rb +25 -0
  60. data/spec/vagrant-openstack-provider/command/volume_list_spec.rb +10 -2
  61. data/spec/vagrant-openstack-provider/config_resolver_spec.rb +680 -0
  62. data/spec/vagrant-openstack-provider/config_spec.rb +15 -1
  63. data/spec/vagrant-openstack-provider/spec_helper.rb +3 -0
  64. data/spec/vagrant-openstack-provider/utils_spec.rb +103 -0
  65. data/vagrant-openstack-provider.gemspec +4 -2
  66. metadata +78 -11
  67. data/Appraisals +0 -13
  68. data/gemfiles/oldest_current.gemfile +0 -20
@@ -6,7 +6,7 @@ module VagrantPlugins
6
6
  class AbstractCommand < Vagrant.plugin('2', :command)
7
7
  def initialize(argv, env)
8
8
  @env = env
9
- super(argv, env)
9
+ super(normalize_args(argv), env)
10
10
  end
11
11
 
12
12
  def execute(name)
@@ -22,6 +22,15 @@ module VagrantPlugins
22
22
  @env.ui.info('')
23
23
  end
24
24
 
25
+ #
26
+ # Before Vagrant 1.5, args list ends with an extra arg '--'. It removes it if present.
27
+ #
28
+ def normalize_args(args)
29
+ return args if args.nil?
30
+ args.pop if args.size > 0 && args.last == '--'
31
+ args
32
+ end
33
+
25
34
  def cmd(_name, _argv, _env)
26
35
  fail 'Command not implemented. \'cmd\' method must be overridden in all subclasses'
27
36
  end
@@ -11,7 +11,7 @@ module VagrantPlugins
11
11
  I18n.t('vagrant_openstack.command.flavor_list_synopsis')
12
12
  end
13
13
  def cmd(name, argv, env)
14
- fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0 || argv == ['--']
14
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
15
15
  flavors = env[:openstack_client].nova.get_all_flavors(env)
16
16
 
17
17
  rows = []
@@ -11,7 +11,7 @@ module VagrantPlugins
11
11
  I18n.t('vagrant_openstack.command.flaotingip_list_synopsis')
12
12
  end
13
13
  def cmd(name, argv, env)
14
- fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0 || argv == ['--']
14
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
15
15
 
16
16
  floating_ip_pools = env[:openstack_client].nova.get_floating_ip_pools(env)
17
17
  floating_ips = env[:openstack_client].nova.get_floating_ips(env)
@@ -11,7 +11,7 @@ module VagrantPlugins
11
11
  I18n.t('vagrant_openstack.command.image_list_synopsis')
12
12
  end
13
13
  def cmd(name, argv, env)
14
- fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0 || argv == ['--']
14
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
15
15
  images = env[:openstack_client].nova.get_all_images(env)
16
16
  display_item_list(env, images)
17
17
  end
@@ -6,7 +6,8 @@ module VagrantPlugins
6
6
  { name: :'flavor-list', file: 'flavor_list', clazz: 'FlavorList' },
7
7
  { name: :'network-list', file: 'network_list', clazz: 'NetworkList' },
8
8
  { name: :'floatingip-list', file: 'floatingip_list', clazz: 'FloatingIpList' },
9
- { name: :'volume-list', file: 'volume_list', clazz: 'VolumeList' }
9
+ { name: :'volume-list', file: 'volume_list', clazz: 'VolumeList' },
10
+ { name: :'reset', file: 'reset', clazz: 'Reset' }
10
11
  ]
11
12
 
12
13
  class Main < Vagrant.plugin('2', :command)
@@ -11,8 +11,14 @@ module VagrantPlugins
11
11
  I18n.t('vagrant_openstack.command.network_list_synopsis')
12
12
  end
13
13
  def cmd(name, argv, env)
14
- fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0 || argv == ['--']
15
- flavors = env[:openstack_client].neutron.get_private_networks(env)
14
+ fail Errors::UnrecognizedArgForCommand, cmd: name, arg: argv[1] if argv.size > 1
15
+ if argv.size == 0
16
+ flavors = env[:openstack_client].neutron.get_private_networks(env)
17
+ elsif argv[0] == 'all'
18
+ flavors = env[:openstack_client].neutron.get_all_networks(env)
19
+ else
20
+ fail Errors::UnrecognizedArgForCommand, cmd: name, arg: argv[0]
21
+ end
16
22
  display_item_list(env, flavors)
17
23
  end
18
24
  end
@@ -0,0 +1,21 @@
1
+ require 'vagrant-openstack-provider/command/utils'
2
+ require 'vagrant-openstack-provider/command/abstract_command'
3
+
4
+ module VagrantPlugins
5
+ module Openstack
6
+ module Command
7
+ class Reset < AbstractCommand
8
+ include VagrantPlugins::Openstack::Command::Utils
9
+
10
+ def self.synopsis
11
+ I18n.t('vagrant_openstack.command.reset')
12
+ end
13
+ def cmd(name, argv, env)
14
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
15
+ FileUtils.remove_dir("#{env[:machine].data_dir}")
16
+ env[:ui].info 'Vagrant OpenStack Provider has been reset'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -14,7 +14,7 @@ module VagrantPlugins
14
14
 
15
15
  def display_table(env, headers, rows)
16
16
  table = Terminal::Table.new headings: headers, rows: rows
17
- env[:ui].info("\n#{table}\n")
17
+ env[:ui].info("\n#{table}")
18
18
  end
19
19
  end
20
20
  end
@@ -11,7 +11,7 @@ module VagrantPlugins
11
11
  I18n.t('vagrant_openstack.command.volume_list_synopsis')
12
12
  end
13
13
  def cmd(name, argv, env)
14
- fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0 || argv == ['--']
14
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
15
15
  volumes = env[:openstack_client].cinder.get_all_volumes(env)
16
16
 
17
17
  rows = []
@@ -136,6 +136,11 @@ module VagrantPlugins
136
136
  # @return [Hash]
137
137
  attr_accessor :metadata
138
138
 
139
+ # Flag to enable/disable all SSH actions (to use for instance on private networks)
140
+ #
141
+ # @return [Boolean]
142
+ attr_accessor :ssh_disabled
143
+
139
144
  def initialize
140
145
  @password = UNSET_VALUE
141
146
  @openstack_compute_url = UNSET_VALUE
@@ -164,6 +169,7 @@ module VagrantPlugins
164
169
  @security_groups = UNSET_VALUE
165
170
  @user_data = UNSET_VALUE
166
171
  @metadata = UNSET_VALUE
172
+ @ssh_disabled = UNSET_VALUE
167
173
  end
168
174
 
169
175
  # rubocop:disable Style/CyclomaticComplexity
@@ -191,6 +197,7 @@ module VagrantPlugins
191
197
  @security_groups = nil if @security_groups == UNSET_VALUE
192
198
  @user_data = nil if @user_data == UNSET_VALUE
193
199
  @metadata = nil if @metadata == UNSET_VALUE
200
+ @ssh_disabled = false if @ssh_disabled == UNSET_VALUE
194
201
 
195
202
  # The SSH values by default are nil, and the top-level config
196
203
  # `config.ssh` values are used.
@@ -212,6 +219,7 @@ module VagrantPlugins
212
219
  errors << I18n.t('vagrant_openstack.config.username_required') unless @username
213
220
 
214
221
  validate_ssh_username(machine, errors)
222
+ validate_ssh_timeout(errors)
215
223
 
216
224
  if machine.config.ssh.private_key_path
217
225
  puts I18n.t('vagrant_openstack.config.keypair_name_required').yellow unless @keypair_name || @public_key_path
@@ -231,12 +239,19 @@ module VagrantPlugins
231
239
  { 'Openstack Provider' => errors }
232
240
  end
233
241
 
242
+ private
243
+
234
244
  def validate_ssh_username(machine, errors)
235
245
  puts I18n.t('vagrant_openstack.config.ssh_username_deprecated').yellow if @ssh_username
236
246
  errors << I18n.t('vagrant_openstack.config.ssh_username_required') unless @ssh_username || machine.config.ssh.username
237
247
  end
238
248
 
239
- private
249
+ def validate_ssh_timeout(errors)
250
+ return if @ssh_timeout.nil? || @ssh_timeout == UNSET_VALUE
251
+ @ssh_timeout = Integer(@ssh_timeout) if @ssh_timeout.is_a? String
252
+ rescue ArgumentError
253
+ errors << I18n.t('vagrant_openstack.config.invalid_value_for_parameter', parameter: 'ssh_timeout', value: @ssh_timeout)
254
+ end
240
255
 
241
256
  def valid_uri?(value)
242
257
  uri = URI.parse value
@@ -0,0 +1,262 @@
1
+ module VagrantPlugins
2
+ module Openstack
3
+ class ConfigResolver
4
+ def initialize
5
+ @logger = Log4r::Logger.new('vagrant_openstack::action::config_resolver')
6
+ end
7
+
8
+ def resolve_ssh_port(env)
9
+ machine_config = env[:machine].config
10
+ return machine_config.ssh.port if machine_config.ssh.port
11
+ 22
12
+ end
13
+
14
+ def resolve_flavor(env)
15
+ @logger.info 'Resolving flavor'
16
+ config = env[:machine].provider_config
17
+ nova = env[:openstack_client].nova
18
+ env[:ui].info(I18n.t('vagrant_openstack.finding_flavor'))
19
+ flavors = nova.get_all_flavors(env)
20
+ @logger.info "Finding flavor matching name '#{config.flavor}'"
21
+ flavor = find_matching(flavors, config.flavor)
22
+ fail Errors::NoMatchingFlavor unless flavor
23
+ flavor
24
+ end
25
+
26
+ def resolve_image(env)
27
+ @logger.info 'Resolving image'
28
+ config = env[:machine].provider_config
29
+ return nil if config.image.nil?
30
+ nova = env[:openstack_client].nova
31
+ env[:ui].info(I18n.t('vagrant_openstack.finding_image'))
32
+ images = nova.get_all_images(env)
33
+ @logger.info "Finding image matching name '#{config.image}'"
34
+ image = find_matching(images, config.image)
35
+ fail Errors::NoMatchingImage unless image
36
+ image
37
+ end
38
+
39
+ def resolve_floating_ip(env)
40
+ config = env[:machine].provider_config
41
+ nova = env[:openstack_client].nova
42
+ return config.floating_ip if config.floating_ip
43
+ fail Errors::UnableToResolveFloatingIP unless config.floating_ip_pool
44
+ nova.get_all_floating_ips(env).each do |single|
45
+ return single.ip if single.pool == config.floating_ip_pool && single.instance_id.nil?
46
+ end unless config.floating_ip_pool_always_allocate
47
+ nova.allocate_floating_ip(env, config.floating_ip_pool).ip
48
+ end
49
+
50
+ def resolve_keypair(env)
51
+ config = env[:machine].provider_config
52
+ nova = env[:openstack_client].nova
53
+ return config.keypair_name if config.keypair_name
54
+ return nova.import_keypair_from_file(env, config.public_key_path) if config.public_key_path
55
+ generate_keypair(env)
56
+ end
57
+
58
+ def resolve_networks(env)
59
+ @logger.info 'Resolving network(s)'
60
+ config = env[:machine].provider_config
61
+ return [] if config.networks.nil? || config.networks.empty?
62
+ env[:ui].info(I18n.t('vagrant_openstack.finding_networks'))
63
+ return resolve_networks_without_network_service(env) unless env[:openstack_client].session.endpoints.key? :network
64
+
65
+ private_networks = env[:openstack_client].neutron.get_private_networks(env)
66
+ private_network_ids = private_networks.map { |v| v.id }
67
+
68
+ networks = []
69
+ config.networks.each do |network|
70
+ networks << resolve_network(network, private_networks, private_network_ids)
71
+ end
72
+ @logger.debug("Resolved networks : #{networks.to_json}")
73
+ networks
74
+ end
75
+
76
+ def resolve_volume_boot(env)
77
+ @logger.info 'Resolving image'
78
+ config = env[:machine].provider_config
79
+ return nil if config.volume_boot.nil?
80
+ return resolve_volume_without_volume_service(env, config.volume_boot, 'vda') unless env[:openstack_client].session.endpoints.key? :volume
81
+
82
+ volume_list = env[:openstack_client].cinder.get_all_volumes(env)
83
+ volume_ids = volume_list.map { |v| v.id }
84
+
85
+ @logger.debug(volume_list)
86
+
87
+ volume = resolve_volume(config.volume_boot, volume_list, volume_ids)
88
+ device = volume[:device].nil? ? 'vda' : volume[:device]
89
+
90
+ { id: volume[:id], device: device }
91
+ end
92
+
93
+ def resolve_volumes(env)
94
+ @logger.info 'Resolving volume(s)'
95
+ config = env[:machine].provider_config
96
+ return [] if config.volumes.nil? || config.volumes.empty?
97
+ env[:ui].info(I18n.t('vagrant_openstack.finding_volumes'))
98
+ return resolve_volumes_without_volume_service(env) unless env[:openstack_client].session.endpoints.key? :volume
99
+
100
+ volume_list = env[:openstack_client].cinder.get_all_volumes(env)
101
+ volume_ids = volume_list.map { |v| v.id }
102
+
103
+ @logger.debug(volume_list)
104
+
105
+ volumes = []
106
+ config.volumes.each do |volume|
107
+ volumes << resolve_volume(volume, volume_list, volume_ids)
108
+ end
109
+ @logger.debug("Resolved volumes : #{volumes.to_json}")
110
+ volumes
111
+ end
112
+
113
+ def resolve_ssh_username(env)
114
+ config = env[:machine].provider_config
115
+ machine_config = env[:machine].config
116
+ return machine_config.ssh.username if machine_config.ssh.username
117
+ return config.ssh_username if config.ssh_username
118
+ fail Errors::NoMatchingSshUsername
119
+ end
120
+
121
+ def resolve_security_groups(env)
122
+ groups = []
123
+ env[:machine].provider_config.security_groups.each do |group|
124
+ case group
125
+ when String
126
+ groups << { name: group }
127
+ when Hash
128
+ groups << group
129
+ end
130
+ end unless env[:machine].provider_config.security_groups.nil?
131
+ groups
132
+ end
133
+
134
+ private
135
+
136
+ def generate_keypair(env)
137
+ key = SSHKey.generate
138
+ nova = env[:openstack_client].nova
139
+ generated_keyname = nova.import_keypair(env, key.ssh_public_key)
140
+ file_path = "#{env[:machine].data_dir}/#{generated_keyname}"
141
+ File.write(file_path, key.private_key)
142
+ File.chmod(0600, file_path)
143
+ generated_keyname
144
+ end
145
+
146
+ def resolve_networks_without_network_service(env)
147
+ config = env[:machine].provider_config
148
+ networks = []
149
+ config.networks.each do |network|
150
+ case network
151
+ when String
152
+ env[:ui].info(I18n.t('vagrant_openstack.warn_network_identifier_is_assumed_to_be_an_id', network: network))
153
+ networks << { uuid: network }
154
+ when Hash
155
+ fail Errors::ConflictNetworkNameId, network: network if network.key?(:name) && network.key?(:id)
156
+ fail Errors::NetworkServiceUnavailable if network.key? :name
157
+ if network.key?(:address)
158
+ networks << { uuid: network[:id], fixed_ip: network[:address] }
159
+ else
160
+ networks << { uuid: network[:id] }
161
+ end
162
+ end
163
+ end
164
+ networks
165
+ end
166
+
167
+ def resolve_network(network, network_list, network_ids)
168
+ return resolve_network_from_string(network, network_list) if network.is_a? String
169
+ return resolve_network_from_hash(network, network_list, network_ids) if network.is_a? Hash
170
+ fail Errors::InvalidNetworkObject, network: network
171
+ end
172
+
173
+ def resolve_network_from_string(network, network_list)
174
+ found_network = find_matching(network_list, network)
175
+ fail Errors::UnresolvedNetwork, network: network if found_network.nil?
176
+ { uuid: found_network.id }
177
+ end
178
+
179
+ def resolve_network_from_hash(network, network_list, network_ids)
180
+ if network.key?(:id)
181
+ fail Errors::ConflictNetworkNameId, network: network if network.key?(:name)
182
+ network_id = network[:id]
183
+ fail Errors::UnresolvedNetworkId, id: network_id unless network_ids.include? network_id
184
+ elsif network.key?(:name)
185
+ network_list.each do |v|
186
+ next unless v.name.eql? network[:name]
187
+ fail Errors::MultipleNetworkName, name: network[:name] unless network_id.nil?
188
+ network_id = v.id
189
+ end
190
+ fail Errors::UnresolvedNetworkName, name: network[:name] unless network_ids.include? network_id
191
+ else
192
+ fail Errors::ConflictNetworkNameId, network: network
193
+ end
194
+ return { uuid: network_id, fixed_ip: network[:address] } if network.key?(:address)
195
+ { uuid: network_id }
196
+ end
197
+
198
+ def resolve_volumes_without_volume_service(env)
199
+ env[:machine].provider_config.volumes.map { |volume| resolve_volume_without_volume_service(env, volume) }
200
+ end
201
+
202
+ def resolve_volume_without_volume_service(env, volume, default_device = nil)
203
+ case volume
204
+ when String
205
+ env[:ui].info(I18n.t('vagrant_openstack.warn_volume_identifier_is_assumed_to_be_an_id', volume: volume))
206
+ return { id: volume, device: default_device }
207
+ when Hash
208
+ fail Errors::ConflictVolumeNameId, volume: volume if volume.key?(:name) && volume.key?(:id)
209
+ fail Errors::VolumeServiceUnavailable if volume.key? :name
210
+ return { id: volume[:id], device: volume[:device] || default_device }
211
+ end
212
+ fail Errors::InvalidVolumeObject, volume: volume
213
+ end
214
+
215
+ def resolve_volume(volume, volume_list, volume_ids)
216
+ return resolve_volume_from_string(volume, volume_list) if volume.is_a? String
217
+ return resolve_volume_from_hash(volume, volume_list, volume_ids) if volume.is_a? Hash
218
+ fail Errors::InvalidVolumeObject, volume: volume
219
+ end
220
+
221
+ def resolve_volume_from_string(volume, volume_list)
222
+ found_volume = find_matching(volume_list, volume)
223
+ fail Errors::UnresolvedVolume, volume: volume if found_volume.nil?
224
+ { id: found_volume.id, device: nil }
225
+ end
226
+
227
+ def resolve_volume_from_hash(volume, volume_list, volume_ids)
228
+ device = nil
229
+ device = volume[:device] if volume.key?(:device)
230
+ if volume.key?(:id)
231
+ fail Errors::ConflictVolumeNameId, volume: volume if volume.key?(:name)
232
+ volume_id = volume[:id]
233
+ fail Errors::UnresolvedVolumeId, id: volume_id unless volume_ids.include? volume_id
234
+ elsif volume.key?(:name)
235
+ volume_list.each do |v|
236
+ next unless v.name.eql? volume[:name]
237
+ fail Errors::MultipleVolumeName, name: volume[:name] unless volume_id.nil?
238
+ volume_id = v.id
239
+ end
240
+ fail Errors::UnresolvedVolumeName, name: volume[:name] unless volume_ids.include? volume_id
241
+ else
242
+ fail Errors::ConflictVolumeNameId, volume: volume
243
+ end
244
+ { id: volume_id, device: device }
245
+ end
246
+
247
+ # This method finds a matching _thing_ in a collection of
248
+ # _things_. This works matching if the ID or NAME equals to
249
+ # `name`. Or, if `name` is a regexp, a partial match is chosen
250
+ # as well.
251
+ def find_matching(collection, name)
252
+ collection.each do |single|
253
+ return single if single.id == name
254
+ return single if single.name == name
255
+ return single if name.is_a?(Regexp) && name =~ single.name
256
+ end
257
+ @logger.error "Element '#{name}' not found in collection #{collection}"
258
+ nil
259
+ end
260
+ end
261
+ end
262
+ end
@@ -52,6 +52,10 @@ module VagrantPlugins
52
52
  error_key(:no_arg_required_for_command)
53
53
  end
54
54
 
55
+ class UnrecognizedArgForCommand < VagrantOpenstackError
56
+ error_key(:unrecognized_arg_for_command)
57
+ end
58
+
55
59
  class UnableToResolveFloatingIP < VagrantOpenstackError
56
60
  error_key(:unable_to_resolve_floating_ip)
57
61
  end
@@ -64,6 +68,30 @@ module VagrantPlugins
64
68
  error_key(:unable_to_resolve_ssh_key)
65
69
  end
66
70
 
71
+ class InvalidNetworkObject < VagrantOpenstackError
72
+ error_key(:invalid_network_format)
73
+ end
74
+
75
+ class UnresolvedNetwork < VagrantOpenstackError
76
+ error_key(:unresolved_network)
77
+ end
78
+
79
+ class UnresolvedNetworkId < VagrantOpenstackError
80
+ error_key(:unresolved_network_id)
81
+ end
82
+
83
+ class UnresolvedNetworkName < VagrantOpenstackError
84
+ error_key(:unresolved_network_name)
85
+ end
86
+
87
+ class ConflictNetworkNameId < VagrantOpenstackError
88
+ error_key(:conflict_network_name_id)
89
+ end
90
+
91
+ class MultipleNetworkName < VagrantOpenstackError
92
+ error_key(:multiple_network_name)
93
+ end
94
+
67
95
  class InvalidVolumeObject < VagrantOpenstackError
68
96
  error_key(:invalid_volume_format)
69
97
  end
@@ -99,6 +127,18 @@ module VagrantPlugins
99
127
  class NoMatchingSshUsername < VagrantOpenstackError
100
128
  error_key(:ssh_username_missing)
101
129
  end
130
+
131
+ class InstanceNotFound < VagrantOpenstackError
132
+ error_key(:instance_not_found)
133
+ end
134
+
135
+ class NetworkServiceUnavailable < VagrantOpenstackError
136
+ error_key(:nerwork_service_unavailable)
137
+ end
138
+
139
+ class VolumeServiceUnavailable < VagrantOpenstackError
140
+ error_key(:volume_service_unavailable)
141
+ end
102
142
  end
103
143
  end
104
144
  end