vagrant-openstack-provider 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/lib/vagrant-openstack-provider.rb +2 -31
  4. data/lib/vagrant-openstack-provider/action.rb +21 -7
  5. data/lib/vagrant-openstack-provider/action/abstract_action.rb +22 -0
  6. data/lib/vagrant-openstack-provider/action/connect_openstack.rb +19 -40
  7. data/lib/vagrant-openstack-provider/action/create_server.rb +10 -6
  8. data/lib/vagrant-openstack-provider/action/create_stack.rb +67 -0
  9. data/lib/vagrant-openstack-provider/action/delete_server.rb +28 -3
  10. data/lib/vagrant-openstack-provider/action/delete_stack.rb +72 -0
  11. data/lib/vagrant-openstack-provider/action/message.rb +4 -2
  12. data/lib/vagrant-openstack-provider/action/read_ssh_info.rb +4 -2
  13. data/lib/vagrant-openstack-provider/action/read_state.rb +9 -4
  14. data/lib/vagrant-openstack-provider/action/resume.rb +4 -2
  15. data/lib/vagrant-openstack-provider/action/start_server.rb +4 -2
  16. data/lib/vagrant-openstack-provider/action/stop_server.rb +4 -2
  17. data/lib/vagrant-openstack-provider/action/suspend.rb +4 -2
  18. data/lib/vagrant-openstack-provider/action/sync_folders.rb +17 -13
  19. data/lib/vagrant-openstack-provider/action/wait_accessible.rb +5 -2
  20. data/lib/vagrant-openstack-provider/action/wait_active.rb +5 -3
  21. data/lib/vagrant-openstack-provider/action/wait_stop.rb +5 -3
  22. data/lib/vagrant-openstack-provider/catalog/openstack_catalog.rb +66 -0
  23. data/lib/vagrant-openstack-provider/client/domain.rb +41 -1
  24. data/lib/vagrant-openstack-provider/client/glance.rb +63 -0
  25. data/lib/vagrant-openstack-provider/client/heat.rb +50 -0
  26. data/lib/vagrant-openstack-provider/client/http_utils.rb +18 -0
  27. data/lib/vagrant-openstack-provider/client/neutron.rb +9 -15
  28. data/lib/vagrant-openstack-provider/client/nova.rb +3 -3
  29. data/lib/vagrant-openstack-provider/client/openstack.rb +10 -0
  30. data/lib/vagrant-openstack-provider/command/abstract_command.rb +7 -0
  31. data/lib/vagrant-openstack-provider/command/image_list.rb +12 -2
  32. data/lib/vagrant-openstack-provider/command/main.rb +1 -0
  33. data/lib/vagrant-openstack-provider/command/network_list.rb +3 -3
  34. data/lib/vagrant-openstack-provider/command/subnet_list.rb +25 -0
  35. data/lib/vagrant-openstack-provider/config.rb +78 -7
  36. data/lib/vagrant-openstack-provider/config_resolver.rb +36 -5
  37. data/lib/vagrant-openstack-provider/errors.rb +30 -2
  38. data/lib/vagrant-openstack-provider/logging.rb +39 -0
  39. data/lib/vagrant-openstack-provider/version.rb +1 -1
  40. data/locales/en.yml +107 -4
  41. data/spec/vagrant-openstack-provider/action/connect_openstack_spec.rb +255 -8
  42. data/spec/vagrant-openstack-provider/action/create_server_spec.rb +6 -1
  43. data/spec/vagrant-openstack-provider/action/create_stack_spec.rb +97 -0
  44. data/spec/vagrant-openstack-provider/action/delete_server_spec.rb +34 -6
  45. data/spec/vagrant-openstack-provider/action/delete_stack_spec.rb +64 -0
  46. data/spec/vagrant-openstack-provider/action/read_state_spec.rb +13 -1
  47. data/spec/vagrant-openstack-provider/action/sync_folders_spec.rb +1 -0
  48. data/spec/vagrant-openstack-provider/action/wait_active_spec.rb +1 -1
  49. data/spec/vagrant-openstack-provider/action/wait_stop_spec.rb +1 -1
  50. data/spec/vagrant-openstack-provider/client/glance_spec.rb +128 -0
  51. data/spec/vagrant-openstack-provider/client/heat_spec.rb +124 -0
  52. data/spec/vagrant-openstack-provider/client/neutron_spec.rb +33 -1
  53. data/spec/vagrant-openstack-provider/client/nova_spec.rb +2 -2
  54. data/spec/vagrant-openstack-provider/command/image_list_spec.rb +75 -23
  55. data/spec/vagrant-openstack-provider/command/subnet_list_spec.rb +46 -0
  56. data/spec/vagrant-openstack-provider/config_resolver_spec.rb +85 -19
  57. data/spec/vagrant-openstack-provider/config_spec.rb +177 -1
  58. data/spec/vagrant-openstack-provider/spec_helper.rb +3 -0
  59. metadata +20 -2
@@ -21,9 +21,30 @@ module VagrantPlugins
21
21
  end
22
22
  end
23
23
 
24
+ class Image < Item
25
+ attr_accessor :visibility
26
+ attr_accessor :size
27
+ attr_accessor :min_ram
28
+ attr_accessor :min_disk
29
+
30
+ def initialize(id, name, visibility = nil, size = nil, min_ram = nil, min_disk = nil)
31
+ @visibility = visibility
32
+ @size = size
33
+ @min_ram = min_ram
34
+ @min_disk = min_disk
35
+ super(id, name)
36
+ end
37
+
38
+ protected
39
+
40
+ def state
41
+ [@id, @name, @visibility, @size, @min_ram, @min_disk]
42
+ end
43
+ end
44
+
24
45
  class Flavor < Item
25
46
  #
26
- # THe number of vCPU
47
+ # The number of vCPU
27
48
  #
28
49
  attr_accessor :vcpus
29
50
 
@@ -115,6 +136,25 @@ module VagrantPlugins
115
136
  [@id, @name, @size, @status, @bootable, @instance_id, @device]
116
137
  end
117
138
  end
139
+
140
+ class Subnet < Item
141
+ attr_accessor :cidr
142
+ attr_accessor :enable_dhcp
143
+ attr_accessor :network_id
144
+
145
+ def initialize(id, name, cidr, enable_dhcp, network_id)
146
+ @cidr = cidr
147
+ @enable_dhcp = enable_dhcp
148
+ @network_id = network_id
149
+ super(id, name)
150
+ end
151
+
152
+ protected
153
+
154
+ def state
155
+ [@id, @name, @cidr, @enable_dhcp, @network_id]
156
+ end
157
+ end
118
158
  end
119
159
  end
120
160
  end
@@ -0,0 +1,63 @@
1
+ require 'log4r'
2
+ require 'restclient'
3
+ require 'json'
4
+
5
+ require 'vagrant-openstack-provider/client/http_utils'
6
+ require 'vagrant-openstack-provider/client/domain'
7
+
8
+ module VagrantPlugins
9
+ module Openstack
10
+ class GlanceClient
11
+ include Singleton
12
+ include VagrantPlugins::Openstack::HttpUtils
13
+ include VagrantPlugins::Openstack::Domain
14
+
15
+ def initialize
16
+ @logger = Log4r::Logger.new('vagrant_openstack::glance')
17
+ @session = VagrantPlugins::Openstack.session
18
+ end
19
+
20
+ def get_api_version_list(_env)
21
+ json = RestClient.get(@session.endpoints[:image], 'X-Auth-Token' => @session.token, :accept => :json) do |response|
22
+ log_response(response)
23
+ case response.code
24
+ when 200, 300
25
+ response
26
+ when 401
27
+ fail Errors::AuthenticationFailed
28
+ else
29
+ fail Errors::VagrantOpenstackError, message: response.to_s
30
+ end
31
+ end
32
+ JSON.parse(json)['versions']
33
+ end
34
+
35
+ # Endpoint /images exists on both v1 and v2 API
36
+ # The attribute 'visibility' is used to detect
37
+ # if the call has been made on v1 or v2
38
+ #
39
+ # In case of v2 we have all the needed information,
40
+ # but in case of v1 we don't and we have to call
41
+ # /images/detail to get full details
42
+ #
43
+ def get_all_images(env)
44
+ images_json = get(env, "#{@session.endpoints[:image]}/images")
45
+ images = JSON.parse(images_json)['images']
46
+
47
+ return images if images.empty?
48
+
49
+ is_v1 = false
50
+ unless images[0].key? 'visibility'
51
+ is_v1 = true
52
+ images_json = get(env, "#{@session.endpoints[:image]}/images/detail")
53
+ images = JSON.parse(images_json)['images']
54
+ end
55
+
56
+ images.map do |i|
57
+ i['visibility'] = i['is_public'] ? 'public' : 'private' if is_v1
58
+ Image.new(i['id'], i['name'], i['visibility'], i['size'], i['min_ram'], i['min_disk'])
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,50 @@
1
+ require 'log4r'
2
+ require 'restclient'
3
+ require 'json'
4
+
5
+ require 'vagrant-openstack-provider/client/http_utils'
6
+ require 'vagrant-openstack-provider/client/domain'
7
+
8
+ module VagrantPlugins
9
+ module Openstack
10
+ class HeatClient
11
+ include Singleton
12
+ include VagrantPlugins::Openstack::HttpUtils
13
+ include VagrantPlugins::Openstack::Domain
14
+
15
+ def initialize
16
+ @logger = Log4r::Logger.new('vagrant_openstack::glance')
17
+ @session = VagrantPlugins::Openstack.session
18
+ end
19
+
20
+ def create_stack(env, options)
21
+ stack = {}.tap do |s|
22
+ s['stack_name'] = options[:name] if options[:name]
23
+ s['template'] = options[:template]
24
+ end
25
+ stack_res = post(env, "#{@session.endpoints[:orchestration]}/stacks", stack.to_json)
26
+ JSON.parse(stack_res)['stack']['id']
27
+ end
28
+
29
+ def get_stack_details(env, stack_name, stack_id)
30
+ stack_exists do
31
+ server_details = get(env, "#{@session.endpoints[:orchestration]}/stacks/#{stack_name}/#{stack_id}")
32
+ JSON.parse(server_details)['stack']
33
+ end
34
+ end
35
+
36
+ def delete_stack(env, stack_name, stack_id)
37
+ stack_exists do
38
+ delete(env, "#{@session.endpoints[:orchestration]}/stacks/#{stack_name}/#{stack_id}")
39
+ end
40
+ end
41
+
42
+ def stack_exists
43
+ return yield
44
+ rescue Errors::VagrantOpenstackError => e
45
+ raise Errors::StackNotFound if e.extra_data[:code] == 404
46
+ raise e
47
+ end
48
+ end
49
+ end
50
+ end
@@ -55,6 +55,24 @@ module VagrantPlugins
55
55
  end
56
56
  end
57
57
 
58
+ def get_api_version_list(service_type)
59
+ url = @session.endpoints[service_type]
60
+ headers = { 'X-Auth-Token' => @session.token, :accept => :json }
61
+ log_request(:GET, url, headers)
62
+ json = RestClient.get(url, headers) do |response|
63
+ log_response(response)
64
+ case response.code
65
+ when 200, 300
66
+ response
67
+ when 401
68
+ fail Errors::AuthenticationFailed
69
+ else
70
+ fail Errors::VagrantOpenstackError, message: response.to_s
71
+ end
72
+ end
73
+ JSON.parse(json)['versions']
74
+ end
75
+
58
76
  private
59
77
 
60
78
  ERRORS =
@@ -17,21 +17,6 @@ module VagrantPlugins
17
17
  @session = VagrantPlugins::Openstack.session
18
18
  end
19
19
 
20
- def get_api_version_list(_env)
21
- json = RestClient.get(@session.endpoints[:network], 'X-Auth-Token' => @session.token, :accept => :json) do |response|
22
- log_response(response)
23
- case response.code
24
- when 200, 300
25
- response
26
- when 401
27
- fail Errors::AuthenticationFailed
28
- else
29
- fail Errors::VagrantOpenstackError, message: response.to_s
30
- end
31
- end
32
- JSON.parse(json)['versions']
33
- end
34
-
35
20
  def get_private_networks(env)
36
21
  get_networks(env, false)
37
22
  end
@@ -40,6 +25,15 @@ module VagrantPlugins
40
25
  get_networks(env, true)
41
26
  end
42
27
 
28
+ def get_subnets(env)
29
+ subnets_json = get(env, "#{@session.endpoints[:network]}/subnets")
30
+ subnets = []
31
+ JSON.parse(subnets_json)['subnets'].each do |n|
32
+ subnets << Subnet.new(n['id'], n['name'], n['cidr'], n['enable_dhcp'], n['network_id'])
33
+ end
34
+ subnets
35
+ end
36
+
43
37
  private
44
38
 
45
39
  def get_networks(env, all)
@@ -45,7 +45,7 @@ module VagrantPlugins
45
45
 
46
46
  def get_all_images(env)
47
47
  images_json = get(env, "#{@session.endpoints[:compute]}/images")
48
- JSON.parse(images_json)['images'].map { |fl| Item.new(fl['id'], fl['name']) }
48
+ JSON.parse(images_json)['images'].map { |fl| Image.new(fl['id'], fl['name'], 'unknown') }
49
49
  end
50
50
 
51
51
  def create_server(env, options)
@@ -193,9 +193,9 @@ module VagrantPlugins
193
193
  JSON.parse(ip_details)['floating_ips'].each do |ip|
194
194
  next unless ip['ip'] == floating_ip
195
195
  return if ip['instance_id'].nil?
196
- fail "Floating IP #{floating_ip} already assigned to another server"
196
+ fail Errors::FloatingIPAlreadyAssigned, floating_ip: floating_ip
197
197
  end
198
- fail "Floating IP #{floating_ip} not available for this tenant"
198
+ fail Errors::FloatingIPNotAvailable, floating_ip: floating_ip
199
199
  end
200
200
  end
201
201
  end
@@ -2,10 +2,12 @@ require 'log4r'
2
2
  require 'restclient'
3
3
  require 'json'
4
4
 
5
+ require 'vagrant-openstack-provider/client/heat'
5
6
  require 'vagrant-openstack-provider/client/keystone'
6
7
  require 'vagrant-openstack-provider/client/nova'
7
8
  require 'vagrant-openstack-provider/client/neutron'
8
9
  require 'vagrant-openstack-provider/client/cinder'
10
+ require 'vagrant-openstack-provider/client/glance'
9
11
 
10
12
  module VagrantPlugins
11
13
  module Openstack
@@ -39,6 +41,10 @@ module VagrantPlugins
39
41
  Openstack::NovaClient.instance
40
42
  end
41
43
 
44
+ def self.heat
45
+ Openstack::HeatClient.instance
46
+ end
47
+
42
48
  def self.neutron
43
49
  Openstack::NeutronClient.instance
44
50
  end
@@ -46,5 +52,9 @@ module VagrantPlugins
46
52
  def self.cinder
47
53
  Openstack::CinderClient.instance
48
54
  end
55
+
56
+ def self.glance
57
+ Openstack::GlanceClient.instance
58
+ end
49
59
  end
50
60
  end
@@ -20,7 +20,14 @@ module VagrantPlugins
20
20
 
21
21
  cmd(name, @argv, env)
22
22
  @env.ui.info('')
23
+ # rubocop:disable Lint/RescueException
24
+ rescue Errors::VagrantOpenstackError, SystemExit, Interrupt => e
25
+ raise e
26
+ rescue Exception => e
27
+ puts I18n.t('vagrant_openstack.global_error').red unless e.message && e.message.start_with?('Catched Error:')
28
+ raise e
23
29
  end
30
+ # rubocop:enable Lint/RescueException
24
31
 
25
32
  #
26
33
  # Before Vagrant 1.5, args list ends with an extra arg '--'. It removes it if present.
@@ -12,8 +12,18 @@ module VagrantPlugins
12
12
  end
13
13
  def cmd(name, argv, env)
14
14
  fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
15
- images = env[:openstack_client].nova.get_all_images(env)
16
- display_item_list(env, images)
15
+ rows = []
16
+ headers = %w(Id Name)
17
+ if env[:openstack_client].session.endpoints.key? :image
18
+ images = env[:openstack_client].glance.get_all_images(env)
19
+ images.each { |i| rows << [i.id, i.name, i.visibility, i.size.to_i / 1024 / 1024, i.min_ram, i.min_disk] }
20
+ headers << ['Visibility', 'Size (Mo)', 'Min RAM (Go)', 'Min Disk (Go)']
21
+ headers = headers.flatten
22
+ else
23
+ images = env[:openstack_client].nova.get_all_images(env)
24
+ images.each { |image| rows << [image.id, image.name] }
25
+ end
26
+ display_table(env, headers, rows)
17
27
  end
18
28
  end
19
29
  end
@@ -5,6 +5,7 @@ module VagrantPlugins
5
5
  { name: :'image-list', file: 'image_list' , clazz: 'ImageList' },
6
6
  { name: :'flavor-list', file: 'flavor_list', clazz: 'FlavorList' },
7
7
  { name: :'network-list', file: 'network_list', clazz: 'NetworkList' },
8
+ { name: :'subnet-list', file: 'subnet_list', clazz: 'SubnetList' },
8
9
  { name: :'floatingip-list', file: 'floatingip_list', clazz: 'FloatingIpList' },
9
10
  { name: :'volume-list', file: 'volume_list', clazz: 'VolumeList' },
10
11
  { name: :'reset', file: 'reset', clazz: 'Reset' }
@@ -13,13 +13,13 @@ module VagrantPlugins
13
13
  def cmd(name, argv, env)
14
14
  fail Errors::UnrecognizedArgForCommand, cmd: name, arg: argv[1] if argv.size > 1
15
15
  if argv.size == 0
16
- flavors = env[:openstack_client].neutron.get_private_networks(env)
16
+ networks = env[:openstack_client].neutron.get_private_networks(env)
17
17
  elsif argv[0] == 'all'
18
- flavors = env[:openstack_client].neutron.get_all_networks(env)
18
+ networks = env[:openstack_client].neutron.get_all_networks(env)
19
19
  else
20
20
  fail Errors::UnrecognizedArgForCommand, cmd: name, arg: argv[0]
21
21
  end
22
- display_item_list(env, flavors)
22
+ display_item_list(env, networks)
23
23
  end
24
24
  end
25
25
  end
@@ -0,0 +1,25 @@
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 SubnetList < AbstractCommand
8
+ include VagrantPlugins::Openstack::Command::Utils
9
+
10
+ def self.synopsis
11
+ I18n.t('vagrant_openstack.command.subnet_list_synopsis')
12
+ end
13
+
14
+ def cmd(name, argv, env)
15
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
16
+ rows = []
17
+ env[:openstack_client].neutron.get_subnets(env).each do |subnet|
18
+ rows << [subnet.id, subnet.name, subnet.cidr, subnet.enable_dhcp, subnet.network_id]
19
+ end
20
+ display_table(env, ['Id', 'Name', 'CIDR', 'DHCP', 'Network Id'], rows)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -8,24 +8,32 @@ module VagrantPlugins
8
8
  #
9
9
  attr_accessor :password
10
10
 
11
- # The compute service url to access Openstack. If nil, it will read from
12
- # hypermedia catalog form REST API
11
+ # The compute service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
13
12
  #
14
13
  attr_accessor :openstack_compute_url
15
14
 
16
- # The network service url to access Openstack. If nil, it will read from
17
- # hypermedia catalog form REST API
15
+ # The network service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
18
16
  #
19
17
  attr_accessor :openstack_network_url
20
18
 
21
- # The block storage service url to access Openstack. If nil, it will read from
22
- # hypermedia catalog form REST API
19
+ # The block storage service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
23
20
  #
24
21
  attr_accessor :openstack_volume_url
25
22
 
23
+ # The orchestration service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
24
+ #
25
+ attr_accessor :openstack_orchestration_url
26
+
27
+ # The image service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
28
+ #
29
+ attr_accessor :openstack_image_url
30
+
26
31
  # The authentication endpoint. This defaults to Openstack's global authentication endpoint.
27
32
  attr_accessor :openstack_auth_url
28
33
 
34
+ # Openstack region
35
+ attr_accessor :region
36
+
29
37
  # The flavor of server to launch, either the ID or name. This
30
38
  # can also be a regular expression to partially match a name.
31
39
  attr_accessor :flavor
@@ -96,6 +104,12 @@ module VagrantPlugins
96
104
  # @return [String]
97
105
  attr_accessor :sync_method
98
106
 
107
+ # Sync folder ignore files. A list of files containing exclude patterns to ignore in the rsync operation
108
+ # performed by this provider
109
+ #
110
+ # @return [Array]
111
+ attr_accessor :rsync_ignore_files
112
+
99
113
  # Network list the VM will be connected to
100
114
  #
101
115
  # @return [Array]
@@ -106,6 +120,11 @@ module VagrantPlugins
106
120
  # @return [Array]
107
121
  attr_accessor :volumes
108
122
 
123
+ # Stack that will be created and associated to the instances
124
+ #
125
+ # @return [Array]
126
+ attr_accessor :stacks
127
+
109
128
  # Public key path to create OpenStack keypair
110
129
  #
111
130
  # @return [Array]
@@ -146,7 +165,10 @@ module VagrantPlugins
146
165
  @openstack_compute_url = UNSET_VALUE
147
166
  @openstack_network_url = UNSET_VALUE
148
167
  @openstack_volume_url = UNSET_VALUE
168
+ @openstack_orchestration_url = UNSET_VALUE
169
+ @openstack_image_url = UNSET_VALUE
149
170
  @openstack_auth_url = UNSET_VALUE
171
+ @region = UNSET_VALUE
150
172
  @flavor = UNSET_VALUE
151
173
  @image = UNSET_VALUE
152
174
  @volume_boot = UNSET_VALUE
@@ -154,15 +176,17 @@ module VagrantPlugins
154
176
  @server_name = UNSET_VALUE
155
177
  @username = UNSET_VALUE
156
178
  @rsync_includes = []
179
+ @rsync_ignore_files = []
157
180
  @keypair_name = UNSET_VALUE
158
181
  @ssh_username = UNSET_VALUE
159
182
  @ssh_timeout = UNSET_VALUE
160
183
  @floating_ip = UNSET_VALUE
161
- @floating_ip_pool = UNSET_VALUE
184
+ @floating_ip_pool = []
162
185
  @floating_ip_pool_always_allocate = UNSET_VALUE
163
186
  @sync_method = UNSET_VALUE
164
187
  @availability_zone = UNSET_VALUE
165
188
  @networks = []
189
+ @stacks = []
166
190
  @volumes = []
167
191
  @public_key_path = UNSET_VALUE
168
192
  @scheduler_hints = UNSET_VALUE
@@ -172,13 +196,49 @@ module VagrantPlugins
172
196
  @ssh_disabled = UNSET_VALUE
173
197
  end
174
198
 
199
+ def merge(other)
200
+ result = self.class.new
201
+
202
+ # Set all of our instance variables on the new class
203
+ [self, other].each do |obj|
204
+ obj.instance_variables.each do |key|
205
+ # Ignore keys that start with a double underscore. This allows
206
+ # configuration classes to still hold around internal state
207
+ # that isn't propagated.
208
+ next if key.to_s.start_with?('@__')
209
+
210
+ # Let user inputs a string or an array for floating ip pool attribute
211
+ obj.floating_ip_pool = [obj.floating_ip_pool].flatten if key.eql?(:@floating_ip_pool) && !obj.floating_ip_pool.nil?
212
+
213
+ # Don't set the value if it is the unset value, either.
214
+ value = obj.instance_variable_get(key)
215
+
216
+ if [:@networks, :@volumes, :@rsync_includes, :@ignore_files, :@floating_ip_pool, :@stacks].include? key
217
+ result.instance_variable_set(key, value) unless value.empty?
218
+ else
219
+ result.instance_variable_set(key, value) if value != UNSET_VALUE
220
+ end
221
+ end
222
+ end
223
+
224
+ # Persist through the set of invalid methods
225
+ this_invalid = @__invalid_methods || Set.new
226
+ other_invalid = other.instance_variable_get(:"@__invalid_methods") || Set.new
227
+ result.instance_variable_set(:"@__invalid_methods", this_invalid + other_invalid)
228
+
229
+ result
230
+ end
231
+
175
232
  # rubocop:disable Style/CyclomaticComplexity
176
233
  def finalize!
177
234
  @password = nil if @password == UNSET_VALUE
178
235
  @openstack_compute_url = nil if @openstack_compute_url == UNSET_VALUE
179
236
  @openstack_network_url = nil if @openstack_network_url == UNSET_VALUE
237
+ @openstack_orchestration_url = nil if @openstack_orchestration_url == UNSET_VALUE
180
238
  @openstack_volume_url = nil if @openstack_volume_url == UNSET_VALUE
239
+ @openstack_image_url = nil if @openstack_image_url == UNSET_VALUE
181
240
  @openstack_auth_url = nil if @openstack_auth_url == UNSET_VALUE
241
+ @region = nil if @region == UNSET_VALUE
182
242
  @flavor = nil if @flavor == UNSET_VALUE
183
243
  @image = nil if @image == UNSET_VALUE
184
244
  @volume_boot = nil if @volume_boot == UNSET_VALUE
@@ -186,6 +246,7 @@ module VagrantPlugins
186
246
  @server_name = nil if @server_name == UNSET_VALUE
187
247
  @username = nil if @username == UNSET_VALUE
188
248
  @rsync_includes = nil if @rsync_includes.empty?
249
+ @rsync_ignore_files = nil if @rsync_ignore_files.empty?
189
250
  @floating_ip = nil if @floating_ip == UNSET_VALUE
190
251
  @floating_ip_pool = nil if @floating_ip_pool == UNSET_VALUE
191
252
  @floating_ip_pool_always_allocate = false if floating_ip_pool_always_allocate == UNSET_VALUE
@@ -205,6 +266,7 @@ module VagrantPlugins
205
266
  @ssh_timeout = 180 if @ssh_timeout == UNSET_VALUE
206
267
  @networks = nil if @networks.empty?
207
268
  @volumes = nil if @volumes.empty?
269
+ @stacks = nil if @stacks.empty?
208
270
  end
209
271
  # rubocop:enable Style/CyclomaticComplexity
210
272
 
@@ -219,6 +281,7 @@ module VagrantPlugins
219
281
  errors << I18n.t('vagrant_openstack.config.username_required') unless @username
220
282
 
221
283
  validate_ssh_username(machine, errors)
284
+ validate_stack_config(errors)
222
285
  validate_ssh_timeout(errors)
223
286
 
224
287
  if machine.config.ssh.private_key_path
@@ -231,6 +294,8 @@ module VagrantPlugins
231
294
  openstack_compute_url: @openstack_compute_url,
232
295
  openstack_network_url: @openstack_network_url,
233
296
  openstack_volume_url: @openstack_volume_url,
297
+ openstack_orchestration_url: @openstack_orchestration_url,
298
+ openstack_image_url: @openstack_image_url,
234
299
  openstack_auth_url: @openstack_auth_url
235
300
  }.each_pair do |key, value|
236
301
  errors << I18n.t('vagrant_openstack.config.invalid_uri', key: key, uri: value) unless value.nil? || valid_uri?(value)
@@ -241,6 +306,12 @@ module VagrantPlugins
241
306
 
242
307
  private
243
308
 
309
+ def validate_stack_config(errors)
310
+ @stacks.each do |stack|
311
+ errors << I18n.t('vagrant_openstack.config.invalid_stack') unless stack[:name] && stack[:template]
312
+ end unless @stacks.nil?
313
+ end
314
+
244
315
  def validate_ssh_username(machine, errors)
245
316
  puts I18n.t('vagrant_openstack.config.ssh_username_deprecated').yellow if @ssh_username
246
317
  errors << I18n.t('vagrant_openstack.config.ssh_username_required') unless @ssh_username || machine.config.ssh.username