vagrant-openstack-provider 0.7.2 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4dd7cf830eecfb15611665ed53da19db9cd5bab5
4
- data.tar.gz: 1b5bce071291bc0af764f91933b839803ee3f4c7
3
+ metadata.gz: 609b227799e2765e0d6f7bb5277e7e8602cb424f
4
+ data.tar.gz: d92034eb5c24737dc80912e983e35443e8929550
5
5
  SHA512:
6
- metadata.gz: b95d4b1ccc79200bcd97f7a189e21768b214b3f50056d77ff53c83d7581b31c3d23a3e9d343f7023b37a31e8128a65cf6303c7315af3f3f00906286e634145c5
7
- data.tar.gz: 2f071db27ddf020cb30cbf15bbcb7e11e0944dcf63572418c6fc3ce751d4080da54931172424fc88dc2aacf7fb7011ec8f6cedf17278ed7793e11f770d257e96
6
+ metadata.gz: 34905aff4b10744c0c2402b01d801d76adff1c4be7107c46d55e85be80455dc44046dccf6d46fd7df3694695ceef9eaabbc603fb3eff217438648ad6473a0763
7
+ data.tar.gz: e4cdb6940e49072f44bd79829981dce5b6fbc4b385e7f59528ff8c9a22663e86137f03b1999389168dc888b9aa90b21ec05e2738b114968b9cc4ce024b47afce
@@ -1,3 +1,17 @@
1
+ # 0.8.0 (November 19, 2016)
2
+
3
+ IMPROVEMENTS:
4
+
5
+ - Move to standard Vagrant synced folders middleware #295
6
+
7
+ FEATURES:
8
+
9
+ - Support Keystone v3 API #4
10
+
11
+ BUG FIXES:
12
+
13
+ - Bugfix on IP address resolution #285
14
+
1
15
  # 0.7.2 (May 1, 2016)
2
16
 
3
17
  IMPROVEMENTS:
data/Gemfile CHANGED
@@ -3,7 +3,14 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :development do
6
- gem 'vagrant', git: 'https://github.com/mitchellh/vagrant.git', tag: 'v1.8.1'
6
+ gem 'vagrant', git: 'https://github.com/mitchellh/vagrant.git', tag: 'v1.8.5'
7
+ # FIXME: Hack to allow Vagrant v1.6.5 to install for tests. Remove when
8
+ # support for 1.6.5 is dropped.
9
+ gem 'rack', '< 2'
10
+ # FIXME: Version 1.4.0 of the ruby_dep gem added a constraint on the Ruby
11
+ # version being >=2.2.5. This pin to ruby_dep 1.3.1 can be removed when the
12
+ # next Vagrant version after 1.8.5 is released.
13
+ gem 'ruby_dep', '~> 1.3.1'
7
14
  gem 'appraisal', '1.0.0'
8
15
  gem 'rubocop', '0.29.0', require: false
9
16
  gem 'coveralls', require: false
@@ -39,7 +39,13 @@ module VagrantPlugins
39
39
  else
40
40
  b2.use Provision
41
41
  end
42
- b2.use SyncFolders
42
+ if env[:machine].provider_config.use_legacy_synced_folders
43
+ env[:machine].ui.warn I18n.t('vagrant_openstack.config.sync_folders_deprecated')
44
+ b2.use SyncFolders
45
+ else
46
+ # Standard Vagrant implementation.
47
+ b2.use SyncedFolders
48
+ end
43
49
  end
44
50
  end
45
51
  end
@@ -61,6 +67,7 @@ module VagrantPlugins
61
67
  # key.
62
68
  def self.action_read_state
63
69
  new_builder.tap do |b|
70
+ b.use HandleBox
64
71
  b.use ConfigValidate
65
72
  b.use ConnectOpenstack
66
73
  b.use ReadState
@@ -97,6 +104,7 @@ module VagrantPlugins
97
104
 
98
105
  def self.action_up
99
106
  new_builder.tap do |b|
107
+ b.use HandleBox
100
108
  b.use ConfigValidate
101
109
  b.use ConnectOpenstack
102
110
 
@@ -111,7 +119,15 @@ module VagrantPlugins
111
119
  b2.use Provision
112
120
  end
113
121
  end
114
- b2.use SyncFolders
122
+
123
+ if env[:machine].provider_config.use_legacy_synced_folders
124
+ env[:machine].ui.warn I18n.t('vagrant_openstack.config.sync_folders_deprecated')
125
+ b2.use SyncFolders
126
+ else
127
+ # Standard Vagrant implementation.
128
+ b2.use SyncedFolders
129
+ end
130
+
115
131
  b2.use CreateStack
116
132
  b2.use CreateServer
117
133
  b2.use Message, I18n.t('vagrant_openstack.ssh_disabled_provisioning') if ssh_disabled
@@ -99,7 +99,7 @@ module VagrantPlugins
99
99
  end
100
100
  end
101
101
 
102
- log = "Lauching server '#{server_name}' in project '#{config.tenant_name}' "
102
+ log = "Launching server '#{server_name}' in project '#{config.tenant_name}' "
103
103
  log << "with flavor '#{options[:flavor].name}' (#{options[:flavor].id}), "
104
104
  unless options[:image].nil?
105
105
  log << "image '#{options[:image].name}' (#{options[:image].id}) "
@@ -131,7 +131,7 @@ module VagrantPlugins
131
131
  @logger.info "Waiting for the server with id #{server_id} to be built..."
132
132
  env[:ui].info(I18n.t('vagrant_openstack.waiting_for_build'))
133
133
  config = env[:machine].provider_config
134
- timeout(config.server_create_timeout, Errors::Timeout) do
134
+ Timeout.timeout(config.server_create_timeout, Errors::Timeout) do
135
135
  server_status = 'WAITING'
136
136
  until server_status == 'ACTIVE'
137
137
  @logger.debug('Waiting for server to be ACTIVE')
@@ -60,7 +60,7 @@ module VagrantPlugins
60
60
  @logger.info "Waiting for the stack with id #{stack_id} to be built..."
61
61
  env[:ui].info(I18n.t('vagrant_openstack.waiting_for_stack'))
62
62
  config = env[:machine].provider_config
63
- timeout(config.stack_create_timeout, Errors::Timeout) do
63
+ Timeout.timeout(config.stack_create_timeout, Errors::Timeout) do
64
64
  stack_status = 'CREATE_IN_PROGRESS'
65
65
  until stack_status == 'CREATE_COMPLETE'
66
66
  @logger.debug('Waiting for stack to be CREATED')
@@ -32,7 +32,7 @@ module VagrantPlugins
32
32
  @logger.info "Waiting for the instance with id #{instance_id} to be deleted..."
33
33
  env[:ui].info(I18n.t('vagrant_openstack.waiting_deleted'))
34
34
  config = env[:machine].provider_config
35
- timeout(config.server_delete_timeout, Errors::Timeout) do
35
+ Timeout.timeout(config.server_delete_timeout, Errors::Timeout) do
36
36
  delete_ok = false
37
37
  until delete_ok
38
38
  begin
@@ -57,7 +57,7 @@ module VagrantPlugins
57
57
  @logger.info "Waiting for the stack with id #{stack_id} to be deleted..."
58
58
  env[:ui].info(I18n.t('vagrant_openstack.waiting_for_stack_deleted'))
59
59
  config = env[:machine].provider_config
60
- timeout(config.stack_delete_timeout, Errors::Timeout) do
60
+ Timeout.timeout(config.stack_delete_timeout, Errors::Timeout) do
61
61
  stack_status = 'DELETE_IN_PROGRESS'
62
62
  until stack_status == 'DELETE_COMPLETE'
63
63
  @logger.debug('Waiting for stack to be DELETED')
@@ -18,7 +18,7 @@ module VagrantPlugins
18
18
  env[:ui].info(I18n.t('vagrant_openstack.waiting_start'))
19
19
  client = env[:openstack_client].nova
20
20
  config = env[:machine].provider_config
21
- timeout(config.server_active_timeout, Errors::Timeout) do
21
+ Timeout.timeout(config.server_active_timeout, Errors::Timeout) do
22
22
  while client.get_server_details(env, env[:machine].id)['status'] != 'ACTIVE'
23
23
  sleep @retry_interval
24
24
  @logger.info('Waiting for server to be active')
@@ -18,7 +18,7 @@ module VagrantPlugins
18
18
  env[:ui].info(I18n.t('vagrant_openstack.waiting_stop'))
19
19
  client = env[:openstack_client].nova
20
20
  config = env[:machine].provider_config
21
- timeout(config.server_stop_timeout, Errors::Timeout) do
21
+ Timeout.timeout(config.server_stop_timeout, Errors::Timeout) do
22
22
  while client.get_server_details(env, env[:machine].id)['status'] != 'SHUTOFF'
23
23
  sleep @retry_interval
24
24
  @logger.info('Waiting for server to stop')
@@ -10,24 +10,16 @@ module VagrantPlugins
10
10
  config = env[:machine].provider_config
11
11
  client = env[:openstack_client]
12
12
  endpoints = client.session.endpoints
13
- endpoint_type = config.endpoint_type
14
13
  @logger.info(I18n.t('vagrant_openstack.client.looking_for_available_endpoints'))
15
14
  @logger.info("Selecting endpoints matching region '#{config.region}'") unless config.region.nil?
16
15
 
17
16
  catalog.each do |service|
18
17
  se = service['endpoints']
19
- if config.region.nil?
20
- if se.size > 1
21
- env[:ui].warn I18n.t('vagrant_openstack.client.multiple_endpoint', size: se.size, type: service['type'])
22
- env[:ui].warn " => #{service['endpoints'][0][endpoint_type]}"
23
- end
24
- url = se[0][endpoint_type].strip
25
- else
26
- se.each do |endpoint|
27
- url = endpoint[endpoint_type].strip if endpoint['region'].eql? config.region
28
- end
18
+ if config.identity_api_version == '2'
19
+ get_endpoints_2(env, se, service, config, endpoints)
20
+ elsif config.identity_api_version == '3'
21
+ get_interfaces_3(se, service, config, endpoints)
29
22
  end
30
- endpoints[service['type'].to_sym] = url unless url.nil? || url.empty?
31
23
  end
32
24
 
33
25
  endpoints[:network] = choose_api_version('Neutron', 'openstack_network_url', 'v2') do
@@ -41,6 +33,37 @@ module VagrantPlugins
41
33
 
42
34
  private
43
35
 
36
+ def get_endpoints_2(env, se, service, config, endpoints)
37
+ endpoint_type = config.endpoint_type
38
+ if config.region.nil?
39
+ if se.size > 1
40
+ env[:ui].warn I18n.t('vagrant_openstack.client.multiple_endpoint', size: se.size, type: service['type'])
41
+ env[:ui].warn " => #{service['endpoints'][0][endpoint_type]}"
42
+ end
43
+ url = se[0][endpoint_type].strip
44
+ else
45
+ se.each do |endpoint|
46
+ url = endpoint[endpoint_type].strip if endpoint['region'].eql? config.region
47
+ end
48
+ end
49
+ endpoints[service['type'].to_sym] = url unless url.nil? || url.empty?
50
+ end
51
+
52
+ def get_interfaces_3(se, service, config, endpoints)
53
+ url = nil
54
+ se.each do |endpoint|
55
+ next if endpoint['interface'] != config.interface_type
56
+ if config.region.nil?
57
+ url = endpoint['url']
58
+ break
59
+ elsif endpoint['region'] == config.region
60
+ url = endpoint['url']
61
+ break
62
+ end
63
+ end
64
+ endpoints[service['type'].to_sym] = url unless url.nil? || url.empty?
65
+ end
66
+
44
67
  def choose_api_version(service_name, url_property, version_prefix = nil, fail_if_not_found = true)
45
68
  versions = yield
46
69
 
@@ -19,20 +19,13 @@ module VagrantPlugins
19
19
  config = env[:machine].provider_config
20
20
  @logger.info(I18n.t('vagrant_openstack.client.authentication', project: config.tenant_name, user: config.username))
21
21
 
22
- post_body =
23
- {
24
- auth:
25
- {
26
- tenantName: config.tenant_name,
27
- passwordCredentials:
28
- {
29
- username: config.username,
30
- password: '****'
31
- }
32
- }
33
- }
34
-
35
- auth_url = get_auth_url_v2 env
22
+ if config.identity_api_version == '2'
23
+ post_body = get_body_2 config
24
+ auth_url = get_auth_url_2 env
25
+ elsif config.identity_api_version == '3'
26
+ post_body = get_body_3 config
27
+ auth_url = get_auth_url_3 env
28
+ end
36
29
 
37
30
  headers = {
38
31
  content_type: :json,
@@ -41,13 +34,19 @@ module VagrantPlugins
41
34
 
42
35
  log_request(:POST, auth_url, post_body.to_json, headers)
43
36
 
44
- post_body[:auth][:passwordCredentials][:password] = config.password
37
+ if config.identity_api_version == '2'
38
+ post_body[:auth][:passwordCredentials][:password] = config.password
39
+ elsif config.identity_api_version == '3'
40
+ post_body[:auth][:identity][:password][:user][:password] = config.password
41
+ end
45
42
 
46
43
  authentication = RestUtils.post(env, auth_url, post_body.to_json, headers) do |response|
47
44
  log_response(response)
48
45
  case response.code
49
46
  when 200
50
47
  response
48
+ when 201
49
+ response
51
50
  when 401
52
51
  fail Errors::AuthenticationFailed
53
52
  when 404
@@ -57,17 +56,69 @@ module VagrantPlugins
57
56
  end
58
57
  end
59
58
 
60
- access = JSON.parse(authentication)['access']
61
- response_token = access['token']
62
- @session.token = response_token['id']
63
- @session.project_id = response_token['tenant']['id']
64
-
65
- access['serviceCatalog']
59
+ if config.identity_api_version == '2'
60
+ access = JSON.parse(authentication)['access']
61
+ response_token = access['token']
62
+ @session.token = response_token['id']
63
+ @session.project_id = response_token['tenant']['id']
64
+ return access['serviceCatalog']
65
+ elsif config.identity_api_version == '3'
66
+ body = JSON.parse(authentication)
67
+ @session.token = authentication.headers[:x_subject_token]
68
+ @session.project_id = body['token']['project']['id']
69
+ return body['token']['catalog']
70
+ end
66
71
  end
67
72
 
68
73
  private
69
74
 
70
- def get_auth_url_v2(env)
75
+ def get_body_2(config)
76
+ {
77
+ auth:
78
+ {
79
+ tenantName: config.tenant_name,
80
+ passwordCredentials:
81
+ {
82
+ username: config.username,
83
+ password: '****'
84
+ }
85
+ }
86
+ }
87
+ end
88
+
89
+ def get_body_3(config)
90
+ {
91
+ auth:
92
+ {
93
+ identity: {
94
+ methods: ['password'],
95
+ password: {
96
+ user: {
97
+ name: config.username,
98
+ domain: {
99
+ name: config.domain_name
100
+ },
101
+ password: '****'
102
+ }
103
+ }
104
+ },
105
+ scope: {
106
+ project: {
107
+ name: config.project_name,
108
+ domain: { name: config.domain_name }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ end
114
+
115
+ def get_auth_url_3(env)
116
+ url = env[:machine].provider_config.openstack_auth_url
117
+ return url if url.match(%r{/tokens/*$})
118
+ "#{url}/auth/tokens"
119
+ end
120
+
121
+ def get_auth_url_2(env)
71
122
  url = env[:machine].provider_config.openstack_auth_url
72
123
  return url if url.match(%r{/tokens/*$})
73
124
  "#{url}/tokens"
@@ -52,6 +52,11 @@ module VagrantPlugins
52
52
  #
53
53
  attr_accessor :tenant_name
54
54
 
55
+ #
56
+ # The name of the openstack project on witch the vm will be created, changed name in v3 identity API.
57
+ #
58
+ attr_accessor :project_name
59
+
55
60
  # The name of the server. This defaults to the name of the machine
56
61
  # defined by Vagrant (via `config.vm.define`), but can be overriden
57
62
  # here.
@@ -62,6 +67,11 @@ module VagrantPlugins
62
67
  # @return [String]
63
68
  attr_accessor :username
64
69
 
70
+ # The domain name to access Openstack, this defaults to Default.
71
+ #
72
+ # @return [String]
73
+ attr_accessor :domain_name
74
+
65
75
  # The name of the keypair to use.
66
76
  #
67
77
  # @return [String]
@@ -82,6 +92,8 @@ module VagrantPlugins
82
92
 
83
93
  # Opt files/directories in to the rsync operation performed by this provider
84
94
  #
95
+ # @deprecated Use standard Vagrant synced folders instead.
96
+ #
85
97
  # @return [Array]
86
98
  attr_accessor :rsync_includes
87
99
 
@@ -103,12 +115,16 @@ module VagrantPlugins
103
115
 
104
116
  # Sync folder method. Can be either "rsync" or "none"
105
117
  #
118
+ # @deprecated Use standard Vagrant synced folders instead.
119
+ #
106
120
  # @return [String]
107
121
  attr_accessor :sync_method
108
122
 
109
123
  # Sync folder ignore files. A list of files containing exclude patterns to ignore in the rsync operation
110
124
  # performed by this provider
111
125
  #
126
+ # @deprecated Use standard Vagrant synced folders instead.
127
+ #
112
128
  # @return [Array]
113
129
  attr_accessor :rsync_ignore_files
114
130
 
@@ -167,6 +183,16 @@ module VagrantPlugins
167
183
  # @return [String]
168
184
  attr_accessor :endpoint_type
169
185
 
186
+ # Specify the endpoint_type to use : publicL, admin, or internal (default is public)
187
+ #
188
+ # @return [String]
189
+ attr_accessor :interface_type
190
+
191
+ # Specify the authentication version to use : 2 or 3 (ddefault is 2()
192
+ #
193
+ # @return [String]
194
+ attr_accessor :identity_api_version
195
+
170
196
  #
171
197
  # @return [Integer]
172
198
  attr_accessor :server_create_timeout
@@ -199,6 +225,20 @@ module VagrantPlugins
199
225
  # @return [Boolean]
200
226
  attr_accessor :meta_args_support
201
227
 
228
+ # A switch for enabling the legacy synced folders implementation.
229
+ #
230
+ # This defaults to false, but is automatically set to true if any of the
231
+ # legacy synced folder options are used:
232
+ #
233
+ # - {#rsync_includes}
234
+ # - {#rsync_ignore_files}
235
+ # - {#sync_method}
236
+ #
237
+ # @deprecated Use standard Vagrant synced folders instead.
238
+ #
239
+ # @return [Boolean]
240
+ attr_accessor :use_legacy_synced_folders
241
+
202
242
  def initialize
203
243
  @password = UNSET_VALUE
204
244
  @openstack_compute_url = UNSET_VALUE
@@ -208,6 +248,8 @@ module VagrantPlugins
208
248
  @openstack_image_url = UNSET_VALUE
209
249
  @openstack_auth_url = UNSET_VALUE
210
250
  @endpoint_type = UNSET_VALUE
251
+ @interface_type = UNSET_VALUE
252
+ @identity_api_version = UNSET_VALUE
211
253
  @region = UNSET_VALUE
212
254
  @flavor = UNSET_VALUE
213
255
  @image = UNSET_VALUE
@@ -242,6 +284,7 @@ module VagrantPlugins
242
284
  @stack_delete_timeout = UNSET_VALUE
243
285
  @meta_args_support = UNSET_VALUE
244
286
  @http = HttpConfig.new
287
+ @use_legacy_synced_folders = UNSET_VALUE
245
288
  end
246
289
 
247
290
  def merge(other)
@@ -282,7 +325,7 @@ module VagrantPlugins
282
325
  result
283
326
  end
284
327
 
285
- # rubocop:disable Metrics/CyclomaticComplexity
328
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
286
329
  def finalize!
287
330
  @password = nil if @password == UNSET_VALUE
288
331
  @openstack_compute_url = nil if @openstack_compute_url == UNSET_VALUE
@@ -292,19 +335,20 @@ module VagrantPlugins
292
335
  @openstack_image_url = nil if @openstack_image_url == UNSET_VALUE
293
336
  @openstack_auth_url = nil if @openstack_auth_url == UNSET_VALUE
294
337
  @endpoint_type = 'publicURL' if @endpoint_type == UNSET_VALUE
338
+ @interface_type = 'public' if @interface_type == UNSET_VALUE
339
+ @identity_api_version = '2' if @identity_api_version == UNSET_VALUE
295
340
  @region = nil if @region == UNSET_VALUE
296
341
  @flavor = nil if @flavor == UNSET_VALUE
297
342
  @image = nil if @image == UNSET_VALUE
298
343
  @volume_boot = nil if @volume_boot == UNSET_VALUE
299
344
  @tenant_name = nil if @tenant_name == UNSET_VALUE
345
+ @project_name = nil if @project_name == UNSET_VALUE
300
346
  @server_name = nil if @server_name == UNSET_VALUE
301
347
  @username = nil if @username == UNSET_VALUE
302
- @rsync_includes = nil if @rsync_includes.empty?
303
- @rsync_ignore_files = nil if @rsync_ignore_files.empty?
348
+ @domain_name = 'Default' if @domain_name == UNSET_VALUE
304
349
  @floating_ip = nil if @floating_ip == UNSET_VALUE
305
350
  @floating_ip_pool = nil if @floating_ip_pool == UNSET_VALUE
306
351
  @floating_ip_pool_always_allocate = false if floating_ip_pool_always_allocate == UNSET_VALUE
307
- @sync_method = 'rsync' if @sync_method == UNSET_VALUE
308
352
  @keypair_name = nil if @keypair_name == UNSET_VALUE
309
353
  @public_key_path = nil if @public_key_path == UNSET_VALUE
310
354
  @availability_zone = nil if @availability_zone == UNSET_VALUE
@@ -314,6 +358,27 @@ module VagrantPlugins
314
358
  @metadata = nil if @metadata == UNSET_VALUE
315
359
  @ssh_disabled = false if @ssh_disabled == UNSET_VALUE
316
360
 
361
+ # The value of use_legacy_synced_folders is used by action chains
362
+ # to determine which synced folder implementation to run.
363
+ if @use_legacy_synced_folders == UNSET_VALUE
364
+ @use_legacy_synced_folders = !(
365
+ (@rsync_includes.nil? || @rsync_includes.empty?) &&
366
+ (@rsync_ignore_files.nil? || @rsync_ignore_files.empty?) &&
367
+ (@sync_method.nil? || @sync_method == UNSET_VALUE))
368
+ end
369
+
370
+ if @use_legacy_synced_folders
371
+ # Original defaults.
372
+ @rsync_includes = nil if @rsync_includes.empty?
373
+ @rsync_ignore_files = nil if @rsync_ignore_files.empty?
374
+ @sync_method = 'rsync' if @sync_method == UNSET_VALUE
375
+ else
376
+ # Disable all sync settings.
377
+ @rsync_includes = nil
378
+ @rsync_ignore_files = nil
379
+ @sync_method = nil
380
+ end
381
+
317
382
  # The SSH values by default are nil, and the top-level config
318
383
  # `config.ssh` and `config.vm.boot_timeout` values are used.
319
384
  @ssh_username = nil if @ssh_username == UNSET_VALUE
@@ -331,8 +396,10 @@ module VagrantPlugins
331
396
  @stacks = nil if @stacks.empty?
332
397
  @http.finalize!
333
398
  end
334
- # rubocop:enable Metrics/CyclomaticComplexity
399
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
335
400
 
401
+ #
402
+ # @deprecated Use standard Vagrant synced folders instead.
336
403
  def rsync_include(inc)
337
404
  @rsync_includes << inc
338
405
  end
@@ -342,9 +409,9 @@ module VagrantPlugins
342
409
 
343
410
  errors << I18n.t('vagrant_openstack.config.password_required') if @password.nil? || @password.empty?
344
411
  errors << I18n.t('vagrant_openstack.config.username_required') if @username.nil? || @username.empty?
345
- errors << I18n.t('vagrant_openstack.config.tenant_name_required') if @tenant_name.nil? || @tenant_name.empty?
346
- errors << I18n.t('vagrant_openstack.config.invalid_endpoint_type') unless %w(publicURL adminURL internalURL).include?(@endpoint_type)
412
+ errors << I18n.t('vagrant_openstack.config.invalid_api_version') unless %w(2 3).include?(@identity_api_version)
347
413
 
414
+ validate_api_version(errors)
348
415
  validate_ssh_username(machine, errors)
349
416
  validate_stack_config(errors)
350
417
  validate_ssh_timeout(errors)
@@ -371,6 +438,17 @@ module VagrantPlugins
371
438
 
372
439
  private
373
440
 
441
+ def validate_api_version(errors)
442
+ if @identity_api_version == '2'
443
+ errors << I18n.t('vagrant_openstack.config.tenant_name_required') if @tenant_name.nil? || @tenant_name.empty?
444
+ errors << I18n.t('vagrant_openstack.config.invalid_endpoint_type') unless %w(publicURL adminURL internalURL).include?(@endpoint_type)
445
+ elsif @identity_api_version == '3'
446
+ errors << I18n.t('vagrant_openstack.config.domain_required') if @domain_name.nil? || @domain_name.empty?
447
+ errors << I18n.t('vagrant_openstack.config.project_name_required') if @project_name.nil? || @project_name.empty?
448
+ errors << I18n.t('vagrant_openstack.config.invalid_interface_type') unless %w(public admin internal).include?(@interface_type)
449
+ end
450
+ end
451
+
374
452
  def validate_stack_config(errors)
375
453
  @stacks.each do |stack|
376
454
  errors << I18n.t('vagrant_openstack.config.invalid_stack') unless stack[:name] && stack[:template]
@@ -16,7 +16,12 @@ module VagrantPlugins
16
16
  if addresses.size == 1
17
17
  net_addresses = addresses.first[1]
18
18
  else
19
- net_addresses = addresses[env[:machine].provider_config.networks[0]]
19
+ first_network = env[:machine].provider_config.networks[0]
20
+ if first_network.is_a? String
21
+ net_addresses = addresses[first_network]
22
+ else
23
+ net_addresses = addresses[first_network[:name]]
24
+ end
20
25
  end
21
26
  fail Errors::UnableToResolveIP if net_addresses.size == 0
22
27
  net_addresses[0]['addr']
@@ -4,7 +4,7 @@ module VagrantPlugins
4
4
  # Stable versions must respect the pattern given
5
5
  # by VagrantPlugins::Openstack::VERSION_PATTERN
6
6
  #
7
- VERSION = '0.7.2'
7
+ VERSION = '0.8.0'
8
8
 
9
9
  #
10
10
  # Stable version must respect the naming convention 'x.y.z'
@@ -65,7 +65,7 @@ module VagrantPlugins
65
65
 
66
66
  # rubocop:disable Lint/HandleExceptions
67
67
  def self.check_version
68
- timeout(3, Errors::Timeout) do
68
+ Timeout.timeout(3, Errors::Timeout) do
69
69
  VersionChecker.instance.check
70
70
  end
71
71
  rescue
@@ -138,6 +138,19 @@ en:
138
138
  to the standard vagrant configuration option `config.vm.boot_timeout`.
139
139
  invalid_value_for_parameter: |-
140
140
  Invalid value '%{value}' for parameter '%{parameter}'
141
+ sync_folders_deprecated: |-
142
+ The following configuration settings are deprecated and should be
143
+ removed: rsync_includes, rsync_ignore_files, sync_method. Using these
144
+ settings causes the OpenStack provider to fall back to an old synced
145
+ folder implementation instead of using standard Vagrant synced folders.
146
+ domain_required: |-
147
+ A domain is required when using identity API version 3
148
+ project_name_required: |-
149
+ A project name is required when using identity API version 3
150
+ invalid_interface_type: |-
151
+ Interface type must be public, admin or internal (if not provided, default is public)
152
+ invalid_api_version: |-
153
+ identity API verison must be 2 or 3 (if nto provided, default is 2)
141
154
 
142
155
  errors:
143
156
  default: |-
@@ -18,10 +18,13 @@ describe VagrantPlugins::Openstack::Action::ConnectOpenstack do
18
18
  config.stub(:openstack_volume_url) { nil }
19
19
  config.stub(:openstack_image_url) { nil }
20
20
  config.stub(:tenant_name) { 'testTenant' }
21
+ config.stub(:project_name) { 'testTenant' }
21
22
  config.stub(:username) { 'username' }
22
23
  config.stub(:password) { 'password' }
23
24
  config.stub(:region) { nil }
24
25
  config.stub(:endpoint_type) { 'publicURL' }
26
+ config.stub(:interface_type) { 'public' }
27
+ config.stub(:identity_api_version) { '2' }
25
28
  end
26
29
  end
27
30
 
@@ -243,6 +246,78 @@ describe VagrantPlugins::Openstack::Action::ConnectOpenstack do
243
246
  end
244
247
  end
245
248
 
249
+ context 'with one endpoint by service v3' do
250
+ it 'read service catalog and stores endpoints URL in session v3' do
251
+ catalog = [
252
+ {
253
+ 'endpoints' => [
254
+ {
255
+ 'url' => 'http://nova/v2/projectId',
256
+ 'interface' => 'public',
257
+ 'region' => 'RegionOne',
258
+ 'id' => '1'
259
+ }
260
+ ],
261
+ 'type' => 'compute',
262
+ 'name' => 'nova'
263
+ },
264
+ {
265
+ 'endpoints' => [
266
+ {
267
+ 'url' => 'http://neutron',
268
+ 'interface' => 'public',
269
+ 'region' => 'RegionOne',
270
+ 'id' => '2'
271
+ }
272
+ ],
273
+ 'type' => 'network',
274
+ 'name' => 'neutron'
275
+ },
276
+ {
277
+ 'endpoints' => [
278
+ {
279
+ 'url' => 'http://cinder/v2/projectId',
280
+ 'interface' => 'public',
281
+ 'region' => 'RegionOne',
282
+ 'id' => '2'
283
+ }
284
+ ],
285
+ 'type' => 'volume',
286
+ 'name' => 'cinder'
287
+ },
288
+ {
289
+ 'endpoints' => [
290
+ {
291
+ 'url' => 'http://glance',
292
+ 'interface' => 'public',
293
+ 'region' => 'RegionOne',
294
+ 'id' => '2'
295
+ }
296
+ ],
297
+ 'type' => 'image',
298
+ 'name' => 'glance'
299
+ }
300
+ ]
301
+
302
+ double.tap do |keystone|
303
+ keystone.stub(:authenticate).with(anything) { catalog }
304
+ env[:openstack_client].stub(:keystone) { keystone }
305
+ end
306
+ env[:openstack_client].stub(:neutron) { neutron }
307
+ env[:openstack_client].stub(:glance) { glance }
308
+ config.stub(:domain_name) { 'dummy' }
309
+ config.stub(:identity_api_version) { '3' }
310
+
311
+ @action.call(env)
312
+
313
+ expect(env[:openstack_client].session.endpoints)
314
+ .to eq(compute: 'http://nova/v2/projectId',
315
+ network: 'http://neutron/v2.0',
316
+ volume: 'http://cinder/v2/projectId',
317
+ image: 'http://glance/v2.0')
318
+ end
319
+ end
320
+
246
321
  context 'with multiple regions' do
247
322
  it 'read service catalog and stores endpoints URL for desired regions in session' do
248
323
  catalog = [
@@ -17,6 +17,9 @@ describe VagrantPlugins::Openstack::KeystoneClient do
17
17
  config.stub(:username) { 'username' }
18
18
  config.stub(:password) { 'password' }
19
19
  config.stub(:http) { http }
20
+ config.stub(:interface_type) { 'public' }
21
+ config.stub(:identity_api_version) { '2' }
22
+ config.stub(:project_name) { 'testTenant' }
20
23
  end
21
24
  end
22
25
 
@@ -52,6 +55,29 @@ describe VagrantPlugins::Openstack::KeystoneClient do
52
55
  ]}}'
53
56
  end
54
57
 
58
+ let(:keystone_response_headers_v3) do
59
+ {
60
+ 'Accept' => 'application/json',
61
+ 'Content-Type' => 'application/json',
62
+ 'x_subject_token' => '0123456789'
63
+ }
64
+ end
65
+
66
+ let(:keystone_request_body_v3) do
67
+ '{"auth":{"identity":{"methods":["password"],"password":{"user":{"name":"username","domain":'\
68
+ '{"name":"dummy"},"password":"password"}}},"scope":{"project":{"name":"testTenant","domain":'\
69
+ '{"name":"dummy"}}}}}'
70
+ end
71
+
72
+ let(:keystone_response_body_v3) do
73
+ '{"token":{"is_domain":false,"methods":["password"],"roles":[{"id":"1234","name":"_member_"}],
74
+ "is_admin_project":false,"project":{"domain":{"id":"1234","name":"dummy"},"id":"012345678910",
75
+ "name":"testTenantId"},"catalog":[
76
+ {"endpoints":[{"id":"eid1","interface":"public","url":"http://nova"}],"type":"compute"},
77
+ {"endpoints":[{"id":"eid2","interface":"public","url":"http://neutron"}],"type":"network"}
78
+ ]}}'
79
+ end
80
+
55
81
  before :each do
56
82
  @keystone_client = VagrantPlugins::Openstack.keystone
57
83
  end
@@ -146,5 +172,53 @@ describe VagrantPlugins::Openstack::KeystoneClient do
146
172
  end
147
173
  end
148
174
  end
175
+
176
+ # V3
177
+ context 'with good credentials v3' do
178
+ it 'store token and tenant id' do
179
+ config.stub(:domain_name) { 'dummy' }
180
+ config.stub(:identity_api_version) { '3' }
181
+ config.stub(:openstack_auth_url) { 'http://keystoneAuthV3' }
182
+
183
+ stub_request(:post, 'http://keystoneAuthV3/auth/tokens')
184
+ .with(
185
+ body: keystone_request_body_v3,
186
+ headers: keystone_request_headers)
187
+ .to_return(
188
+ status: 200,
189
+ body: keystone_response_body_v3,
190
+ headers: keystone_response_headers_v3)
191
+
192
+ @keystone_client.authenticate(env)
193
+
194
+ session.token.should eq('0123456789')
195
+ session.project_id.should eq('012345678910')
196
+ end
197
+ end
198
+
199
+ context 'with wrong credentials v3' do
200
+ it 'raise an unauthorized error ' do
201
+ config.stub(:domain_name) { 'dummy' }
202
+ config.stub(:identity_api_version) { '3' }
203
+ config.stub(:openstack_auth_url) { 'http://keystoneAuthV3' }
204
+
205
+ stub_request(:post, 'http://keystoneAuthV3/auth/tokens')
206
+ .with(
207
+ body: keystone_request_body_v3,
208
+ headers: keystone_request_headers)
209
+ .to_return(
210
+ status: 401,
211
+ body: '{
212
+ "error": {
213
+ "message": "The request you have made requires authentication.",
214
+ "code": 401,
215
+ "title": "Unauthorized"
216
+ }
217
+ }',
218
+ headers: keystone_response_headers_v3)
219
+
220
+ expect { @keystone_client.authenticate(env) }.to raise_error(Errors::AuthenticationFailed)
221
+ end
222
+ end
149
223
  end
150
224
  end
@@ -16,7 +16,10 @@ describe VagrantPlugins::Openstack::Config do
16
16
  its(:image) { should be_nil }
17
17
  its(:server_name) { should be_nil }
18
18
  its(:username) { should be_nil }
19
+ its(:use_legacy_synced_folders) { should eq(false) }
19
20
  its(:rsync_includes) { should be_nil }
21
+ its(:rsync_ignore_files) { should be_nil }
22
+ its(:sync_method) { should be_nil }
20
23
  its(:keypair_name) { should be_nil }
21
24
  its(:public_key_path) { should be_nil }
22
25
  its(:availability_zone) { should be_nil }
@@ -55,11 +58,36 @@ describe VagrantPlugins::Openstack::Config do
55
58
  end
56
59
  end
57
60
 
61
+ describe 'use_legacy_synced_folders' do
62
+ it 'should default to true if sync_method is set' do
63
+ subject.sync_method = 'rsync'
64
+ subject.finalize!
65
+
66
+ expect(subject.use_legacy_synced_folders).to eq(true)
67
+ end
68
+
69
+ it 'should default to true if rsync_includes is non-empty' do
70
+ subject.rsync_includes = ['some/file']
71
+ subject.finalize!
72
+
73
+ expect(subject.use_legacy_synced_folders).to eq(true)
74
+ end
75
+
76
+ it 'should default to true if rsync_ignore_files is non-empty' do
77
+ subject.rsync_ignore_files = ['some/file']
78
+ subject.finalize!
79
+
80
+ expect(subject.use_legacy_synced_folders).to eq(true)
81
+ end
82
+ end
83
+
58
84
  it 'should not default rsync_includes if overridden' do
59
85
  inc = 'core'
60
86
  subject.send(:rsync_include, inc)
61
87
  subject.finalize!
62
- subject.send(:rsync_includes).should include(inc)
88
+
89
+ expect(subject.rsync_includes).to include(inc)
90
+ expect(subject.use_legacy_synced_folders).to eq(true)
63
91
  end
64
92
  end
65
93
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-openstack-provider
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillaume Giamarchi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-30 00:00:00.000000000 Z
12
+ date: 2016-11-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json