vagrant-openstack-provider 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -5
  3. data/CHANGELOG.md +18 -0
  4. data/Gemfile +3 -2
  5. data/{LICENSE.txt → LICENSE} +2 -1
  6. data/lib/vagrant-openstack-provider/action.rb +3 -2
  7. data/lib/vagrant-openstack-provider/action/provision.rb +60 -0
  8. data/lib/vagrant-openstack-provider/action/read_ssh_info.rb +4 -0
  9. data/lib/vagrant-openstack-provider/client/domain.rb +2 -2
  10. data/lib/vagrant-openstack-provider/client/keystone.rb +17 -6
  11. data/lib/vagrant-openstack-provider/client/nova.rb +14 -3
  12. data/lib/vagrant-openstack-provider/command/abstract_command.rb +1 -0
  13. data/lib/vagrant-openstack-provider/command/main.rb +1 -3
  14. data/lib/vagrant-openstack-provider/config.rb +3 -3
  15. data/lib/vagrant-openstack-provider/config_resolver.rb +46 -16
  16. data/lib/vagrant-openstack-provider/errors.rb +15 -0
  17. data/lib/vagrant-openstack-provider/plugin.rb +7 -1
  18. data/lib/vagrant-openstack-provider/version.rb +11 -1
  19. data/lib/vagrant-openstack-provider/version_checker.rb +76 -0
  20. data/locales/en.yml +21 -4
  21. data/spec/vagrant-openstack-provider/action/connect_openstack_spec.rb +17 -19
  22. data/spec/vagrant-openstack-provider/action/create_server_spec.rb +19 -18
  23. data/spec/vagrant-openstack-provider/action/create_stack_spec.rb +4 -6
  24. data/spec/vagrant-openstack-provider/action/delete_server_spec.rb +4 -6
  25. data/spec/vagrant-openstack-provider/action/delete_stack_spec.rb +1 -2
  26. data/spec/vagrant-openstack-provider/action/message_spec.rb +1 -2
  27. data/spec/vagrant-openstack-provider/action/provision_spec.rb +104 -0
  28. data/spec/vagrant-openstack-provider/action/read_ssh_info_spec.rb +1 -3
  29. data/spec/vagrant-openstack-provider/action/read_state_spec.rb +1 -2
  30. data/spec/vagrant-openstack-provider/action/resume_server_spec.rb +1 -2
  31. data/spec/vagrant-openstack-provider/action/start_server_spec.rb +1 -2
  32. data/spec/vagrant-openstack-provider/action/stop_server_spec.rb +1 -2
  33. data/spec/vagrant-openstack-provider/action/suspend_server_spec.rb +1 -2
  34. data/spec/vagrant-openstack-provider/action/sync_folders_spec.rb +1 -2
  35. data/spec/vagrant-openstack-provider/action/wait_accessible_spec.rb +1 -2
  36. data/spec/vagrant-openstack-provider/action/wait_active_spec.rb +3 -4
  37. data/spec/vagrant-openstack-provider/action/wait_stop_spec.rb +3 -4
  38. data/spec/vagrant-openstack-provider/action_spec.rb +0 -1
  39. data/spec/vagrant-openstack-provider/client/cinder_spec.rb +5 -8
  40. data/spec/vagrant-openstack-provider/client/glance_spec.rb +69 -70
  41. data/spec/vagrant-openstack-provider/client/heat_spec.rb +24 -28
  42. data/spec/vagrant-openstack-provider/client/keystone_spec.rb +34 -16
  43. data/spec/vagrant-openstack-provider/client/neutron_spec.rb +76 -80
  44. data/spec/vagrant-openstack-provider/client/nova_spec.rb +198 -168
  45. data/spec/vagrant-openstack-provider/client/utils_spec.rb +1 -3
  46. data/spec/vagrant-openstack-provider/command/flavor_list_spec.rb +1 -2
  47. data/spec/vagrant-openstack-provider/command/floatingip_list_spec.rb +1 -2
  48. data/spec/vagrant-openstack-provider/command/image_list_spec.rb +1 -6
  49. data/spec/vagrant-openstack-provider/command/network_list_spec.rb +1 -3
  50. data/spec/vagrant-openstack-provider/command/reset_spec.rb +1 -2
  51. data/spec/vagrant-openstack-provider/command/subnet_list_spec.rb +1 -2
  52. data/spec/vagrant-openstack-provider/command/volume_list_spec.rb +1 -2
  53. data/spec/vagrant-openstack-provider/config_resolver_spec.rb +100 -6
  54. data/spec/vagrant-openstack-provider/config_spec.rb +2 -6
  55. data/spec/vagrant-openstack-provider/e2e_spec.rb.save +27 -0
  56. data/spec/vagrant-openstack-provider/spec_helper.rb +1 -0
  57. data/spec/vagrant-openstack-provider/utils_spec.rb +1 -2
  58. data/spec/vagrant-openstack-provider/version_checker_spec.rb +39 -0
  59. data/vagrant-openstack-provider.gemspec +4 -2
  60. metadata +29 -9
  61. data/gemfiles/latest_stable.gemfile +0 -10
  62. data/gemfiles/minimal_release.gemfile +0 -10
  63. data/gemfiles/previous_release.gemfile +0 -10
@@ -22,7 +22,7 @@ describe VagrantPlugins::Openstack::NovaClient do
22
22
  end
23
23
 
24
24
  let(:env) do
25
- Hash.new.tap do |env|
25
+ {}.tap do |env|
26
26
  env[:ui] = double('ui')
27
27
  env[:ui].stub(:info).with(anything)
28
28
  env[:machine] = double('machine')
@@ -45,19 +45,18 @@ describe VagrantPlugins::Openstack::NovaClient do
45
45
  context 'stack not found' do
46
46
  it 'raise an StackNotFound error' do
47
47
  stub_request(:get, 'http://heat/a1b2c3/stacks/stack_name/stack_id')
48
- .with(
49
- headers:
50
- {
51
- 'Accept' => 'application/json',
52
- 'Accept-Encoding' => 'gzip, deflate',
53
- 'X-Auth-Token' => '123456'
54
- })
55
- .to_return(
56
- status: 404,
57
- body: '{"itemNotFound": {"message": "Stack could not be found", "code": 404}}')
48
+ .with(
49
+ headers:
50
+ {
51
+ 'Accept' => 'application/json',
52
+ 'Accept-Encoding' => 'gzip, deflate',
53
+ 'X-Auth-Token' => '123456'
54
+ })
55
+ .to_return(
56
+ status: 404,
57
+ body: '{"itemNotFound": {"message": "Stack could not be found", "code": 404}}')
58
58
 
59
59
  expect { @heat_client.get_stack_details(env, 'stack_name', 'stack_id') }.to raise_error(VagrantPlugins::Openstack::Errors::StackNotFound)
60
-
61
60
  end
62
61
  end
63
62
  end
@@ -65,17 +64,16 @@ describe VagrantPlugins::Openstack::NovaClient do
65
64
  describe 'create_stack' do
66
65
  context 'with token and project_id acquainted' do
67
66
  it 'returns new stack id' do
68
-
69
67
  stub_request(:post, 'http://heat/a1b2c3/stacks')
70
- .with(
71
- body: '{"stack_name":"stck","template":"toto"}',
72
- headers:
73
- {
74
- 'Accept' => 'application/json',
75
- 'Content-Type' => 'application/json',
76
- 'X-Auth-Token' => '123456'
77
- })
78
- .to_return(status: 202, body: '{ "stack": { "id": "o1o2o3" } }')
68
+ .with(
69
+ body: '{"stack_name":"stck","template":"toto"}',
70
+ headers:
71
+ {
72
+ 'Accept' => 'application/json',
73
+ 'Content-Type' => 'application/json',
74
+ 'X-Auth-Token' => '123456'
75
+ })
76
+ .to_return(status: 202, body: '{ "stack": { "id": "o1o2o3" } }')
79
77
 
80
78
  stack_id = @heat_client.create_stack(env, name: 'stck', template: 'toto')
81
79
 
@@ -87,14 +85,13 @@ describe VagrantPlugins::Openstack::NovaClient do
87
85
  describe 'get_stack_details' do
88
86
  context 'with token and project_id acquainted' do
89
87
  it 'returns stack details' do
90
-
91
88
  stub_request(:get, 'http://heat/a1b2c3/stacks/stack_id/stack_name')
92
- .with(headers:
89
+ .with(headers:
93
90
  {
94
91
  'Accept' => 'application/json',
95
92
  'X-Auth-Token' => '123456'
96
93
  })
97
- .to_return(status: 200, body: '
94
+ .to_return(status: 200, body: '
98
95
  {
99
96
  "stack": {
100
97
  "description": "sample stack",
@@ -116,14 +113,13 @@ describe VagrantPlugins::Openstack::NovaClient do
116
113
  describe 'delete_stack' do
117
114
  context 'with token and project_id acquainted' do
118
115
  it 'deletes the stack' do
119
-
120
116
  stub_request(:delete, 'http://heat/a1b2c3/stacks/stack_id/stack_name')
121
- .with(headers:
117
+ .with(headers:
122
118
  {
123
119
  'Accept' => 'application/json',
124
120
  'X-Auth-Token' => '123456'
125
121
  })
126
- .to_return(status: 204)
122
+ .to_return(status: 204)
127
123
 
128
124
  @heat_client.delete_stack(env, 'stack_id', 'stack_name')
129
125
  end
@@ -1,7 +1,6 @@
1
1
  require 'vagrant-openstack-provider/spec_helper'
2
2
 
3
3
  describe VagrantPlugins::Openstack::KeystoneClient do
4
-
5
4
  let(:http) do
6
5
  double('http').tap do |http|
7
6
  http.stub(:read_timeout) { 42 }
@@ -11,7 +10,7 @@ describe VagrantPlugins::Openstack::KeystoneClient do
11
10
 
12
11
  let(:config) do
13
12
  double('config').tap do |config|
14
- config.stub(:openstack_auth_url) { 'http://keystoneAuthV2' }
13
+ config.stub(:openstack_auth_url) { 'http://keystoneAuthV2/tokens' }
15
14
  config.stub(:openstack_compute_url) { nil }
16
15
  config.stub(:openstack_network_url) { nil }
17
16
  config.stub(:tenant_name) { 'testTenant' }
@@ -22,7 +21,7 @@ describe VagrantPlugins::Openstack::KeystoneClient do
22
21
  end
23
22
 
24
23
  let(:env) do
25
- Hash.new.tap do |env|
24
+ {}.tap do |env|
26
25
  env[:ui] = double('ui')
27
26
  env[:ui].stub(:info).with(anything)
28
27
  env[:machine] = double('machine')
@@ -35,7 +34,6 @@ describe VagrantPlugins::Openstack::KeystoneClient do
35
34
  end
36
35
 
37
36
  describe 'authenticate' do
38
-
39
37
  let(:keystone_request_headers) do
40
38
  {
41
39
  'Accept' => 'application/json',
@@ -60,11 +58,11 @@ describe VagrantPlugins::Openstack::KeystoneClient do
60
58
 
61
59
  context 'with good credentials' do
62
60
  it 'store token and tenant id' do
63
- stub_request(:post, 'http://keystoneAuthV2')
64
- .with(
61
+ stub_request(:post, 'http://keystoneAuthV2/tokens')
62
+ .with(
65
63
  body: keystone_request_body,
66
64
  headers: keystone_request_headers)
67
- .to_return(
65
+ .to_return(
68
66
  status: 200,
69
67
  body: keystone_response_body,
70
68
  headers: keystone_request_headers)
@@ -78,11 +76,11 @@ describe VagrantPlugins::Openstack::KeystoneClient do
78
76
 
79
77
  context 'with wrong credentials' do
80
78
  it 'raise an unauthorized error' do
81
- stub_request(:post, 'http://keystoneAuthV2')
82
- .with(
79
+ stub_request(:post, 'http://keystoneAuthV2/tokens')
80
+ .with(
83
81
  body: keystone_request_body,
84
82
  headers: keystone_request_headers)
85
- .to_return(
83
+ .to_return(
86
84
  status: 401,
87
85
  body: '{
88
86
  "error": {
@@ -99,24 +97,44 @@ describe VagrantPlugins::Openstack::KeystoneClient do
99
97
 
100
98
  context 'with bad endpoint' do
101
99
  it 'raise a BadAuthenticationEndpoint error' do
102
- stub_request(:post, 'http://keystoneAuthV2')
103
- .with(
100
+ stub_request(:post, 'http://keystoneAuthV2/tokens')
101
+ .with(
104
102
  body: keystone_request_body,
105
103
  headers: keystone_request_headers)
106
- .to_return(
104
+ .to_return(
107
105
  status: 404)
108
106
 
109
107
  expect { @keystone_client.authenticate(env) }.to raise_error(Errors::BadAuthenticationEndpoint)
110
108
  end
111
109
  end
112
110
 
111
+ context 'with /tokens suffix missing in URL' do
112
+ it 'raise add the suffix' do
113
+ config.stub(:openstack_auth_url) { 'http://keystoneAuthV2' }
114
+
115
+ stub_request(:post, 'http://keystoneAuthV2/tokens')
116
+ .with(
117
+ body: keystone_request_body,
118
+ headers: keystone_request_headers)
119
+ .to_return(
120
+ status: 200,
121
+ body: keystone_response_body,
122
+ headers: keystone_request_headers)
123
+
124
+ @keystone_client.authenticate(env)
125
+
126
+ session.token.should eq('0123456789')
127
+ session.project_id.should eq('testTenantId')
128
+ end
129
+ end
130
+
113
131
  context 'with internal server error' do
114
132
  it 'raise a VagrantOpenstackError error with response body as message' do
115
- stub_request(:post, 'http://keystoneAuthV2')
116
- .with(
133
+ stub_request(:post, 'http://keystoneAuthV2/tokens')
134
+ .with(
117
135
  body: keystone_request_body,
118
136
  headers: keystone_request_headers)
119
- .to_return(
137
+ .to_return(
120
138
  status: 500,
121
139
  body: 'Internal server error')
122
140
 
@@ -1,7 +1,6 @@
1
1
  require 'vagrant-openstack-provider/spec_helper'
2
2
 
3
3
  describe VagrantPlugins::Openstack::NeutronClient do
4
-
5
4
  let(:http) do
6
5
  double('http').tap do |http|
7
6
  http.stub(:read_timeout) { 42 }
@@ -16,7 +15,7 @@ describe VagrantPlugins::Openstack::NeutronClient do
16
15
  end
17
16
 
18
17
  let(:env) do
19
- Hash.new.tap do |env|
18
+ {}.tap do |env|
20
19
  env[:machine] = double('machine')
21
20
  env[:machine].stub(:provider_config) { config }
22
21
  end
@@ -36,25 +35,24 @@ describe VagrantPlugins::Openstack::NeutronClient do
36
35
  describe 'get_private_networks' do
37
36
  context 'with token' do
38
37
  it 'returns only private networks for project in session' do
39
-
40
38
  stub_request(:get, 'http://neutron/networks')
41
- .with(
42
- headers:
39
+ .with(
40
+ headers:
41
+ {
42
+ 'Accept' => 'application/json',
43
+ 'X-Auth-Token' => '123456'
44
+ })
45
+ .to_return(
46
+ status: 200,
47
+ body: '
43
48
  {
44
- 'Accept' => 'application/json',
45
- 'X-Auth-Token' => '123456'
46
- })
47
- .to_return(
48
- status: 200,
49
- body: '
50
- {
51
- "networks": [
52
- { "name": "PublicNetwork", "tenant_id": "admin-tenant-id", "id": "net-pub" },
53
- { "name": "net1", "tenant_id": "a1b2c3", "id": "net-1" },
54
- { "name": "net2", "tenant_id": "a1b2c3", "id": "net-2" }
55
- ]
56
- }
57
- ')
49
+ "networks": [
50
+ { "name": "PublicNetwork", "tenant_id": "admin-tenant-id", "id": "net-pub" },
51
+ { "name": "net1", "tenant_id": "a1b2c3", "id": "net-1" },
52
+ { "name": "net2", "tenant_id": "a1b2c3", "id": "net-2" }
53
+ ]
54
+ }
55
+ ')
58
56
 
59
57
  networks = @neutron_client.get_private_networks(env)
60
58
 
@@ -70,25 +68,24 @@ describe VagrantPlugins::Openstack::NeutronClient do
70
68
  describe 'get_all_networks' do
71
69
  context 'with token' do
72
70
  it 'returns all networks for project in session' do
73
-
74
71
  stub_request(:get, 'http://neutron/networks')
75
- .with(
76
- headers:
72
+ .with(
73
+ headers:
74
+ {
75
+ 'Accept' => 'application/json',
76
+ 'X-Auth-Token' => '123456'
77
+ })
78
+ .to_return(
79
+ status: 200,
80
+ body: '
77
81
  {
78
- 'Accept' => 'application/json',
79
- 'X-Auth-Token' => '123456'
80
- })
81
- .to_return(
82
- status: 200,
83
- body: '
84
- {
85
- "networks": [
86
- { "name": "PublicNetwork", "tenant_id": "admin-tenant-id", "id": "net-pub" },
87
- { "name": "net1", "tenant_id": "a1b2c3", "id": "net-1" },
88
- { "name": "net2", "tenant_id": "a1b2c3", "id": "net-2" }
89
- ]
90
- }
91
- ')
82
+ "networks": [
83
+ { "name": "PublicNetwork", "tenant_id": "admin-tenant-id", "id": "net-pub" },
84
+ { "name": "net1", "tenant_id": "a1b2c3", "id": "net-1" },
85
+ { "name": "net2", "tenant_id": "a1b2c3", "id": "net-2" }
86
+ ]
87
+ }
88
+ ')
92
89
 
93
90
  networks = @neutron_client.get_all_networks(env)
94
91
 
@@ -106,25 +103,24 @@ describe VagrantPlugins::Openstack::NeutronClient do
106
103
  describe 'get_subnets' do
107
104
  context 'with token' do
108
105
  it 'returns all available subnets' do
109
-
110
106
  stub_request(:get, 'http://neutron/subnets')
111
- .with(
112
- headers:
113
- {
114
- 'Accept' => 'application/json',
115
- 'X-Auth-Token' => '123456'
116
- })
117
- .to_return(
118
- status: 200,
119
- body: '
120
- {
121
- "subnets": [
122
- { "id": "subnet-01", "name": "Subnet 1", "cidr": "192.168.1.0/24", "enable_dhcp": true, "network_id": "net-01" },
123
- { "id": "subnet-02", "name": "Subnet 2", "cidr": "192.168.2.0/24", "enable_dhcp": false, "network_id": "net-01" },
124
- { "id": "subnet-03", "name": "Subnet 3", "cidr": "192.168.100.0/24", "enable_dhcp": true, "network_id": "net-02" }
125
- ]
126
- }
127
- ')
107
+ .with(
108
+ headers:
109
+ {
110
+ 'Accept' => 'application/json',
111
+ 'X-Auth-Token' => '123456'
112
+ })
113
+ .to_return(
114
+ status: 200,
115
+ body: '
116
+ {
117
+ "subnets": [
118
+ { "id": "subnet-01", "name": "Subnet 1", "cidr": "192.168.1.0/24", "enable_dhcp": true, "network_id": "net-01" },
119
+ { "id": "subnet-02", "name": "Subnet 2", "cidr": "192.168.2.0/24", "enable_dhcp": false, "network_id": "net-01" },
120
+ { "id": "subnet-03", "name": "Subnet 3", "cidr": "192.168.100.0/24", "enable_dhcp": true, "network_id": "net-02" }
121
+ ]
122
+ }
123
+ ')
128
124
 
129
125
  networks = @neutron_client.get_subnets(env)
130
126
 
@@ -139,32 +135,32 @@ describe VagrantPlugins::Openstack::NeutronClient do
139
135
  context 'basic' do
140
136
  it 'returns version list' do
141
137
  stub_request(:get, 'http://neutron/')
142
- .with(header: { 'Accept' => 'application/json' })
143
- .to_return(
144
- status: 200,
145
- body: '{
146
- "versions": [
147
- {
148
- "status": "...",
149
- "id": "v1.0",
150
- "links": [
151
- {
152
- "href": "http://neutron/v1.0",
153
- "rel": "self"
154
- }
155
- ]
156
- },
157
- {
158
- "status": "CURRENT",
159
- "id": "v2.0",
160
- "links": [
161
- {
162
- "href": "http://neutron/v2.0",
163
- "rel": "self"
164
- }
165
- ]
166
- }
167
- ]}')
138
+ .with(header: { 'Accept' => 'application/json' })
139
+ .to_return(
140
+ status: 200,
141
+ body: '{
142
+ "versions": [
143
+ {
144
+ "status": "...",
145
+ "id": "v1.0",
146
+ "links": [
147
+ {
148
+ "href": "http://neutron/v1.0",
149
+ "rel": "self"
150
+ }
151
+ ]
152
+ },
153
+ {
154
+ "status": "CURRENT",
155
+ "id": "v2.0",
156
+ "links": [
157
+ {
158
+ "href": "http://neutron/v2.0",
159
+ "rel": "self"
160
+ }
161
+ ]
162
+ }
163
+ ]}')
168
164
 
169
165
  versions = @neutron_client.get_api_version_list(env, :network)
170
166
 
@@ -31,7 +31,7 @@ describe VagrantPlugins::Openstack::NovaClient do
31
31
  end
32
32
 
33
33
  let(:env) do
34
- Hash.new.tap do |env|
34
+ {}.tap do |env|
35
35
  env[:ui] = double('ui')
36
36
  env[:ui].stub(:info).with(anything)
37
37
  env[:machine] = double('machine')
@@ -54,20 +54,19 @@ describe VagrantPlugins::Openstack::NovaClient do
54
54
  context 'instance not found' do
55
55
  it 'raise an InstanceNotFound error' do
56
56
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
57
- .with(
58
- body: '{"os-start":null}',
59
- headers:
60
- {
61
- 'Accept' => 'application/json',
62
- 'Content-Type' => 'application/json',
63
- 'X-Auth-Token' => '123456'
64
- })
65
- .to_return(
66
- status: 404,
67
- body: '{"itemNotFound": {"message": "Instance could not be found", "code": 404}}')
57
+ .with(
58
+ body: '{"os-start":null}',
59
+ headers:
60
+ {
61
+ 'Accept' => 'application/json',
62
+ 'Content-Type' => 'application/json',
63
+ 'X-Auth-Token' => '123456'
64
+ })
65
+ .to_return(
66
+ status: 404,
67
+ body: '{"itemNotFound": {"message": "Instance could not be found", "code": 404}}')
68
68
 
69
69
  expect { @nova_client.start_server(env, 'o1o2o3') }.to raise_error(VagrantPlugins::Openstack::Errors::InstanceNotFound)
70
-
71
70
  end
72
71
  end
73
72
  end
@@ -76,19 +75,19 @@ describe VagrantPlugins::Openstack::NovaClient do
76
75
  context 'with token and project_id acquainted' do
77
76
  it 'returns all flavors' do
78
77
  stub_request(:get, 'http://nova/a1b2c3/flavors/detail')
79
- .with(
80
- headers:
81
- {
82
- 'Accept' => 'application/json',
83
- 'X-Auth-Token' => '123456'
84
- })
85
- .to_return(
86
- status: 200,
87
- body: '{
88
- "flavors": [
89
- { "id": "f1", "name": "flavor1", "vcpus":"1", "ram": "1024", "disk": "10"},
90
- { "id": "f2", "name": "flavor2", "vcpus":"2", "ram": "2048", "disk": "20"}
91
- ]}')
78
+ .with(
79
+ headers:
80
+ {
81
+ 'Accept' => 'application/json',
82
+ 'X-Auth-Token' => '123456'
83
+ })
84
+ .to_return(
85
+ status: 200,
86
+ body: '{
87
+ "flavors": [
88
+ { "id": "f1", "name": "flavor1", "vcpus":"1", "ram": "1024", "disk": "10"},
89
+ { "id": "f2", "name": "flavor2", "vcpus":"2", "ram": "2048", "disk": "20"}
90
+ ]}')
92
91
 
93
92
  flavors = @nova_client.get_all_flavors(env)
94
93
 
@@ -103,15 +102,15 @@ describe VagrantPlugins::Openstack::NovaClient do
103
102
  context 'with token and project_id acquainted' do
104
103
  it 'returns all images' do
105
104
  stub_request(:get, 'http://nova/a1b2c3/images')
106
- .with(
107
- headers:
108
- {
109
- 'Accept' => 'application/json',
110
- 'X-Auth-Token' => '123456'
111
- })
112
- .to_return(
113
- status: 200,
114
- body: '{ "images": [ { "id": "i1", "name": "image1"}, { "id": "i2", "name": "image2"} ] }')
105
+ .with(
106
+ headers:
107
+ {
108
+ 'Accept' => 'application/json',
109
+ 'X-Auth-Token' => '123456'
110
+ })
111
+ .to_return(
112
+ status: 200,
113
+ body: '{ "images": [ { "id": "i1", "name": "image1"}, { "id": "i2", "name": "image2"} ] }')
115
114
 
116
115
  images = @nova_client.get_all_images(env)
117
116
 
@@ -127,17 +126,16 @@ describe VagrantPlugins::Openstack::NovaClient do
127
126
  describe 'create_server' do
128
127
  context 'with token and project_id acquainted' do
129
128
  it 'returns new instance id' do
130
-
131
129
  stub_request(:post, 'http://nova/a1b2c3/servers')
132
- .with(
133
- body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key"}}',
134
- headers:
135
- {
136
- 'Accept' => 'application/json',
137
- 'Content-Type' => 'application/json',
138
- 'X-Auth-Token' => '123456'
139
- })
140
- .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
130
+ .with(
131
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key"}}',
132
+ headers:
133
+ {
134
+ 'Accept' => 'application/json',
135
+ 'Content-Type' => 'application/json',
136
+ 'X-Auth-Token' => '123456'
137
+ })
138
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
141
139
 
142
140
  instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', networks: nil, keypair: 'key')
143
141
 
@@ -147,17 +145,17 @@ describe VagrantPlugins::Openstack::NovaClient do
147
145
  context 'with all options specified' do
148
146
  it 'returns new instance id' do
149
147
  stub_request(:post, 'http://nova/a1b2c3/servers')
150
- .with(
151
- body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key",'\
152
- '"security_groups":[{"name":"default"}],"user_data":"dXNlcl9kYXRhX3Rlc3Q=\n","metadata":"metadata_test"},'\
153
- '"scheduler_hints":"sched_hints_test"}',
154
- headers:
155
- {
156
- 'Accept' => 'application/json',
157
- 'Content-Type' => 'application/json',
158
- 'X-Auth-Token' => '123456'
159
- })
160
- .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
148
+ .with(
149
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key",'\
150
+ '"security_groups":[{"name":"default"}],"user_data":"dXNlcl9kYXRhX3Rlc3Q=\n","metadata":"metadata_test"},'\
151
+ '"os:scheduler_hints":"sched_hints_test"}',
152
+ headers:
153
+ {
154
+ 'Accept' => 'application/json',
155
+ 'Content-Type' => 'application/json',
156
+ 'X-Auth-Token' => '123456'
157
+ })
158
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
161
159
 
162
160
  instance_id = @nova_client.create_server(
163
161
  env,
@@ -177,9 +175,8 @@ describe VagrantPlugins::Openstack::NovaClient do
177
175
 
178
176
  context 'with two networks' do
179
177
  it 'returns new instance id' do
180
-
181
178
  stub_request(:post, 'http://nova/a1b2c3/servers')
182
- .with(
179
+ .with(
183
180
  body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key","networks":[{"uuid":"net1"},{"uuid":"net2"}]}}',
184
181
  headers:
185
182
  {
@@ -187,7 +184,7 @@ describe VagrantPlugins::Openstack::NovaClient do
187
184
  'Content-Type' => 'application/json',
188
185
  'X-Auth-Token' => '123456'
189
186
  })
190
- .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
187
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
191
188
 
192
189
  instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav',
193
190
  networks: [{ uuid: 'net1' }, { uuid: 'net2' }], keypair: 'key')
@@ -198,9 +195,8 @@ describe VagrantPlugins::Openstack::NovaClient do
198
195
 
199
196
  context 'with availability_zone' do
200
197
  it 'returns new instance id' do
201
-
202
198
  stub_request(:post, 'http://nova/a1b2c3/servers')
203
- .with(
199
+ .with(
204
200
  body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key","availability_zone":"avz"}}',
205
201
  headers:
206
202
  {
@@ -208,7 +204,7 @@ describe VagrantPlugins::Openstack::NovaClient do
208
204
  'Content-Type' => 'application/json',
209
205
  'X-Auth-Token' => '123456'
210
206
  })
211
- .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
207
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
212
208
 
213
209
  instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', keypair: 'key', availability_zone: 'avz')
214
210
 
@@ -216,22 +212,51 @@ describe VagrantPlugins::Openstack::NovaClient do
216
212
  end
217
213
  end
218
214
 
219
- context 'with volume_boot' do
220
- it 'returns new instance id' do
221
-
215
+ context 'with volume_boot creating volume' do
216
+ it 'create bootable volume and returns new instance id' do
222
217
  stub_request(:post, 'http://nova/a1b2c3/servers')
223
- .with(
224
- body: '{"server":{"name":"inst","block_device_mapping":[{"volume_id":"vol","device_name":"vda"}],"flavorRef":"flav","key_name":"key"}}',
218
+ .with(
219
+ body: '{"server":{"name":"inst","block_device_mapping_v2":[{"boot_index":"0","volume_size":"10","uuid":"image_id",'\
220
+ '"device_name":"vda","source_type":"image","destination_type":"volume","delete_on_termination":"false"}],'\
221
+ '"flavorRef":"flav","key_name":"key"}}',
225
222
  headers:
226
- {
227
- 'Accept' => 'application/json',
228
- 'Content-Type' => 'application/json',
229
- 'X-Auth-Token' => '123456'
230
- })
231
- .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
223
+ {
224
+ 'Accept' => 'application/json',
225
+ 'Content-Type' => 'application/json',
226
+ 'X-Auth-Token' => '123456'
227
+ })
228
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
229
+
230
+ instance_id = @nova_client.create_server(env,
231
+ name: 'inst',
232
+ image_ref: nil,
233
+ volume_boot: { image: 'image_id', device: 'vda', size: '10',
234
+ delete_on_destroy: 'false' },
235
+ flavor_ref: 'flav',
236
+ keypair: 'key')
237
+ expect(instance_id).to eq('o1o2o3')
238
+ end
239
+ end
232
240
 
233
- instance_id = @nova_client.create_server(env, name: 'inst', volume_boot: { id: 'vol', device: 'vda' }, flavor_ref: 'flav', keypair: 'key')
241
+ context 'with volume_boot id' do
242
+ it 'returns new instance id' do
243
+ stub_request(:post, 'http://nova/a1b2c3/servers')
244
+ .with(
245
+ body: '{"server":{"name":"inst","block_device_mapping":[{"volume_id":"vol","device_name":"vda"}],'\
246
+ '"flavorRef":"flav","key_name":"key"}}',
247
+ headers:
248
+ {
249
+ 'Accept' => 'application/json',
250
+ 'Content-Type' => 'application/json',
251
+ 'X-Auth-Token' => '123456'
252
+ })
253
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
234
254
 
255
+ instance_id = @nova_client.create_server(env,
256
+ name: 'inst',
257
+ volume_boot: { id: 'vol', device: 'vda' },
258
+ flavor_ref: 'flav',
259
+ keypair: 'key')
235
260
  expect(instance_id).to eq('o1o2o3')
236
261
  end
237
262
  end
@@ -241,17 +266,15 @@ describe VagrantPlugins::Openstack::NovaClient do
241
266
  describe 'delete_server' do
242
267
  context 'with token and project_id acquainted' do
243
268
  it 'returns new instance id' do
244
-
245
269
  stub_request(:delete, 'http://nova/a1b2c3/servers/o1o2o3')
246
- .with(
247
- headers: {
248
- 'Accept' => 'application/json',
249
- 'X-Auth-Token' => '123456'
250
- })
251
- .to_return(status: 204)
270
+ .with(
271
+ headers: {
272
+ 'Accept' => 'application/json',
273
+ 'X-Auth-Token' => '123456'
274
+ })
275
+ .to_return(status: 204)
252
276
 
253
277
  @nova_client.delete_server(env, 'o1o2o3')
254
-
255
278
  end
256
279
  end
257
280
  end
@@ -264,13 +287,13 @@ describe VagrantPlugins::Openstack::NovaClient do
264
287
  Kernel.stub(:rand).and_return(2_036_069_739_008)
265
288
 
266
289
  stub_request(:post, 'http://nova/a1b2c3/os-keypairs')
267
- .with(
268
- body: "{\"keypair\":{\"name\":\"vagrant-generated-pzcvcpa8\",\"public_key\":\"#{ssh_key_content}\"}}",
269
- headers: {
270
- 'Accept' => 'application/json',
271
- 'Content-Type' => 'application/json',
272
- 'X-Auth-Token' => '123456' })
273
- .to_return(status: 200, body: '
290
+ .with(
291
+ body: "{\"keypair\":{\"name\":\"vagrant-generated-pzcvcpa8\",\"public_key\":\"#{ssh_key_content}\"}}",
292
+ headers: {
293
+ 'Accept' => 'application/json',
294
+ 'Content-Type' => 'application/json',
295
+ 'X-Auth-Token' => '123456' })
296
+ .to_return(status: 200, body: '
274
297
  {
275
298
  "keypair": {
276
299
  "name": "created_key_name"
@@ -278,7 +301,6 @@ describe VagrantPlugins::Openstack::NovaClient do
278
301
  }')
279
302
 
280
303
  @nova_client.import_keypair_from_file(env, filename)
281
-
282
304
  end
283
305
  end
284
306
  end
@@ -288,12 +310,12 @@ describe VagrantPlugins::Openstack::NovaClient do
288
310
  context 'with keypair not generated by vagrant' do
289
311
  it 'do nothing' do
290
312
  stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
291
- .with(headers:
313
+ .with(headers:
292
314
  {
293
315
  'Accept' => 'application/json',
294
316
  'X-Auth-Token' => '123456'
295
317
  })
296
- .to_return(status: 200, body: '
318
+ .to_return(status: 200, body: '
297
319
  {
298
320
  "server": {
299
321
  "id": "o1o2o3",
@@ -308,15 +330,15 @@ describe VagrantPlugins::Openstack::NovaClient do
308
330
  context 'with keypair generated by vagrant' do
309
331
  it 'deletes the key on nova' do
310
332
  stub_request(:delete, 'http://nova/a1b2c3/os-keypairs/vagrant-generated-1234')
311
- .with(headers: { 'X-Auth-Token' => '123456' })
312
- .to_return(status: 202)
333
+ .with(headers: { 'X-Auth-Token' => '123456' })
334
+ .to_return(status: 202)
313
335
  stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
314
- .with(headers:
336
+ .with(headers:
315
337
  {
316
338
  'Accept' => 'application/json',
317
339
  'X-Auth-Token' => '123456'
318
340
  })
319
- .to_return(status: 200, body: '
341
+ .to_return(status: 200, body: '
320
342
  {
321
343
  "server": {
322
344
  "id": "o1o2o3",
@@ -328,23 +350,44 @@ describe VagrantPlugins::Openstack::NovaClient do
328
350
  @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
329
351
  end
330
352
  end
353
+ context 'with keypair generated by vagrant and missing in server details' do
354
+ it 'do nothing' do
355
+ stub_request(:delete, 'http://nova/a1b2c3/os-keypairs/vagrant-generated-1234')
356
+ .with(headers: { 'X-Auth-Token' => '123456' })
357
+ .to_return(status: 202)
358
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
359
+ .with(headers:
360
+ {
361
+ 'Accept' => 'application/json',
362
+ 'X-Auth-Token' => '123456'
363
+ })
364
+ .to_return(status: 200, body: '
365
+ {
366
+ "server": {
367
+ "id": "o1o2o3"
368
+ }
369
+ }
370
+ ')
371
+
372
+ @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
373
+ end
374
+ end
331
375
  end
332
376
  end
333
377
 
334
378
  describe 'suspend_server' do
335
379
  context 'with token and project_id acquainted' do
336
380
  it 'returns new instance id' do
337
-
338
381
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
339
- .with(
340
- body: '{"suspend":null}',
341
- headers:
342
- {
343
- 'Accept' => 'application/json',
344
- 'Content-Type' => 'application/json',
345
- 'X-Auth-Token' => '123456'
346
- })
347
- .to_return(status: 202)
382
+ .with(
383
+ body: '{"suspend":null}',
384
+ headers:
385
+ {
386
+ 'Accept' => 'application/json',
387
+ 'Content-Type' => 'application/json',
388
+ 'X-Auth-Token' => '123456'
389
+ })
390
+ .to_return(status: 202)
348
391
 
349
392
  @nova_client.suspend_server(env, 'o1o2o3')
350
393
  end
@@ -354,17 +397,16 @@ describe VagrantPlugins::Openstack::NovaClient do
354
397
  describe 'resume_server' do
355
398
  context 'with token and project_id acquainted' do
356
399
  it 'returns new instance id' do
357
-
358
400
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
359
- .with(
360
- body: '{"resume":null}',
361
- headers:
362
- {
363
- 'Accept' => 'application/json',
364
- 'Content-Type' => 'application/json',
365
- 'X-Auth-Token' => '123456'
366
- })
367
- .to_return(status: 202)
401
+ .with(
402
+ body: '{"resume":null}',
403
+ headers:
404
+ {
405
+ 'Accept' => 'application/json',
406
+ 'Content-Type' => 'application/json',
407
+ 'X-Auth-Token' => '123456'
408
+ })
409
+ .to_return(status: 202)
368
410
 
369
411
  @nova_client.resume_server(env, 'o1o2o3')
370
412
  end
@@ -374,20 +416,18 @@ describe VagrantPlugins::Openstack::NovaClient do
374
416
  describe 'stop_server' do
375
417
  context 'with token and project_id acquainted' do
376
418
  it 'returns new instance id' do
377
-
378
419
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
379
- .with(
380
- body: '{"os-stop":null}',
381
- headers:
382
- {
383
- 'Accept' => 'application/json',
384
- 'Content-Type' => 'application/json',
385
- 'X-Auth-Token' => '123456'
386
- })
387
- .to_return(status: 202)
420
+ .with(
421
+ body: '{"os-stop":null}',
422
+ headers:
423
+ {
424
+ 'Accept' => 'application/json',
425
+ 'Content-Type' => 'application/json',
426
+ 'X-Auth-Token' => '123456'
427
+ })
428
+ .to_return(status: 202)
388
429
 
389
430
  @nova_client.stop_server(env, 'o1o2o3')
390
-
391
431
  end
392
432
  end
393
433
  end
@@ -395,20 +435,18 @@ describe VagrantPlugins::Openstack::NovaClient do
395
435
  describe 'start_server' do
396
436
  context 'with token and project_id acquainted' do
397
437
  it 'returns new instance id' do
398
-
399
438
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
400
- .with(
401
- body: '{"os-start":null}',
402
- headers:
403
- {
404
- 'Accept' => 'application/json',
405
- 'Content-Type' => 'application/json',
406
- 'X-Auth-Token' => '123456'
407
- })
408
- .to_return(status: 202)
439
+ .with(
440
+ body: '{"os-start":null}',
441
+ headers:
442
+ {
443
+ 'Accept' => 'application/json',
444
+ 'Content-Type' => 'application/json',
445
+ 'X-Auth-Token' => '123456'
446
+ })
447
+ .to_return(status: 202)
409
448
 
410
449
  @nova_client.start_server(env, 'o1o2o3')
411
-
412
450
  end
413
451
  end
414
452
  end
@@ -417,14 +455,14 @@ describe VagrantPlugins::Openstack::NovaClient do
417
455
  context 'with token and project_id acquainted' do
418
456
  it 'returns all floating ips' do
419
457
  stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
420
- .with(headers:
458
+ .with(headers:
421
459
  {
422
460
  'Accept' => 'application/json',
423
461
  'Accept-Encoding' => 'gzip, deflate',
424
462
  'User-Agent' => 'Ruby',
425
463
  'X-Auth-Token' => '123456'
426
464
  })
427
- .to_return(status: 200, body: '
465
+ .to_return(status: 200, body: '
428
466
  {
429
467
  "floating_ips": [
430
468
  {"instance_id": "1234",
@@ -460,12 +498,12 @@ describe VagrantPlugins::Openstack::NovaClient do
460
498
  context 'with token and project_id acquainted' do
461
499
  it 'return newly allocated floating_ip' do
462
500
  stub_request(:post, 'http://nova/a1b2c3/os-floating-ips')
463
- .with(body: '{"pool":"pool-1"}',
464
- headers: {
465
- 'Accept' => 'application/json',
466
- 'Content-Type' => 'application/json',
467
- 'X-Auth-Token' => '123456' })
468
- .to_return(status: 200, body: '
501
+ .with(body: '{"pool":"pool-1"}',
502
+ headers: {
503
+ 'Accept' => 'application/json',
504
+ 'Content-Type' => 'application/json',
505
+ 'X-Auth-Token' => '123456' })
506
+ .to_return(status: 200, body: '
469
507
  {
470
508
  "floating_ip": {
471
509
  "instance_id": null,
@@ -487,14 +525,13 @@ describe VagrantPlugins::Openstack::NovaClient do
487
525
  describe 'get_server_details' do
488
526
  context 'with token and project_id acquainted' do
489
527
  it 'returns server details' do
490
-
491
528
  stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
492
- .with(headers:
529
+ .with(headers:
493
530
  {
494
531
  'Accept' => 'application/json',
495
532
  'X-Auth-Token' => '123456'
496
533
  })
497
- .to_return(status: 200, body: '
534
+ .to_return(status: 200, body: '
498
535
  {
499
536
  "server": {
500
537
  "addresses": { "private": [ { "addr": "192.168.0.3", "version": 4 } ] },
@@ -519,23 +556,20 @@ describe VagrantPlugins::Openstack::NovaClient do
519
556
  expect(server['tenant_id']).to eq('openstack')
520
557
  expect(server['image']['id']).to eq('i1')
521
558
  expect(server['flavor']['id']).to eq('1')
522
-
523
559
  end
524
560
  end
525
561
  end
526
562
 
527
563
  describe 'add_floating_ip' do
528
-
529
564
  context 'with token and project_id acquainted and IP available' do
530
565
  it 'returns server details' do
531
-
532
566
  stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
533
- .with(headers:
567
+ .with(headers:
534
568
  {
535
569
  'Accept' => 'application/json',
536
570
  'X-Auth-Token' => '123456'
537
571
  })
538
- .to_return(status: 200, body: '
572
+ .to_return(status: 200, body: '
539
573
  {
540
574
  "floating_ips": [
541
575
  {
@@ -556,14 +590,14 @@ describe VagrantPlugins::Openstack::NovaClient do
556
590
  }')
557
591
 
558
592
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
559
- .with(body: '{"addFloatingIp":{"address":"1.2.3.4"}}',
560
- headers:
593
+ .with(body: '{"addFloatingIp":{"address":"1.2.3.4"}}',
594
+ headers:
561
595
  {
562
596
  'Accept' => 'application/json',
563
597
  'Content-Type' => 'application/json',
564
598
  'X-Auth-Token' => '123456'
565
599
  })
566
- .to_return(status: 202)
600
+ .to_return(status: 202)
567
601
 
568
602
  @nova_client.add_floating_ip(env, 'o1o2o3', '1.2.3.4')
569
603
  end
@@ -571,14 +605,13 @@ describe VagrantPlugins::Openstack::NovaClient do
571
605
 
572
606
  context 'with token and project_id acquainted and IP already in use' do
573
607
  it 'raise an error' do
574
-
575
608
  stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
576
- .with(headers:
609
+ .with(headers:
577
610
  {
578
611
  'Accept' => 'application/json',
579
612
  'X-Auth-Token' => '123456'
580
613
  })
581
- .to_return(status: 200, body: '
614
+ .to_return(status: 200, body: '
582
615
  {
583
616
  "floating_ips": [
584
617
  {
@@ -604,14 +637,13 @@ describe VagrantPlugins::Openstack::NovaClient do
604
637
 
605
638
  context 'with token and project_id acquainted and IP not allocated' do
606
639
  it 'raise an error' do
607
-
608
640
  stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
609
- .with(headers:
641
+ .with(headers:
610
642
  {
611
643
  'Accept' => 'application/json',
612
644
  'X-Auth-Token' => '123456'
613
645
  })
614
- .to_return(status: 200, body: '
646
+ .to_return(status: 200, body: '
615
647
  {
616
648
  "floating_ips": [
617
649
  {
@@ -632,7 +664,6 @@ describe VagrantPlugins::Openstack::NovaClient do
632
664
  describe 'get_floating_ip_pools' do
633
665
  context 'with token and project_id acquainted' do
634
666
  it 'should return floating ip pool' do
635
-
636
667
  stub_request(:get, 'http://nova/a1b2c3/os-floating-ip-pools')
637
668
  .with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => '123456' })
638
669
  .to_return(status: 200, body: '
@@ -659,7 +690,6 @@ describe VagrantPlugins::Openstack::NovaClient do
659
690
  describe 'get_floating_ips' do
660
691
  context 'with token and project_id acquainted' do
661
692
  it 'should return floating ip list' do
662
-
663
693
  stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
664
694
  .with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => '123456' })
665
695
  .to_return(status: 200, body: '
@@ -701,13 +731,13 @@ describe VagrantPlugins::Openstack::NovaClient do
701
731
  context 'with volume id and device' do
702
732
  it 'call the nova api' do
703
733
  stub_request(:post, 'http://nova/a1b2c3/servers/9876/os-volume_attachments')
704
- .with(headers:
734
+ .with(headers:
705
735
  {
706
736
  'Accept' => 'application/json',
707
737
  'X-Auth-Token' => '123456'
708
738
  },
709
- body: '{"volumeAttachment":{"volumeId":"n1n2","device":"/dev/vdg"}}')
710
- .to_return(status: 200, body: '
739
+ body: '{"volumeAttachment":{"volumeId":"n1n2","device":"/dev/vdg"}}')
740
+ .to_return(status: 200, body: '
711
741
  {
712
742
  "volumeAttachment": {
713
743
  "device": "/dev/vdg",