vagrant-openstack-illuin-provider 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rubocop.yml +40 -0
  4. data/CHANGELOG.md +282 -0
  5. data/Gemfile +18 -0
  6. data/RELEASE.md +15 -0
  7. data/Rakefile +25 -0
  8. data/Vagrantfile +20 -0
  9. data/dummy.box +0 -0
  10. data/example_box/README.md +13 -0
  11. data/example_box/metadata.json +3 -0
  12. data/functional_tests/Vagrantfile +58 -0
  13. data/functional_tests/keys/vagrant-openstack +27 -0
  14. data/functional_tests/keys/vagrant-openstack.pub +1 -0
  15. data/functional_tests/run_tests.sh +142 -0
  16. data/lib/vagrant-openstack-illuin-provider.rb +29 -0
  17. data/lib/vagrant-openstack-illuin-provider/action.rb +344 -0
  18. data/lib/vagrant-openstack-illuin-provider/action/abstract_action.rb +22 -0
  19. data/lib/vagrant-openstack-illuin-provider/action/connect_openstack.rb +60 -0
  20. data/lib/vagrant-openstack-illuin-provider/action/create_server.rb +187 -0
  21. data/lib/vagrant-openstack-illuin-provider/action/create_stack.rb +76 -0
  22. data/lib/vagrant-openstack-illuin-provider/action/delete_server.rb +53 -0
  23. data/lib/vagrant-openstack-illuin-provider/action/delete_stack.rb +73 -0
  24. data/lib/vagrant-openstack-illuin-provider/action/message.rb +19 -0
  25. data/lib/vagrant-openstack-illuin-provider/action/provision.rb +60 -0
  26. data/lib/vagrant-openstack-illuin-provider/action/read_ssh_info.rb +74 -0
  27. data/lib/vagrant-openstack-illuin-provider/action/read_state.rb +43 -0
  28. data/lib/vagrant-openstack-illuin-provider/action/resume.rb +24 -0
  29. data/lib/vagrant-openstack-illuin-provider/action/snapshot_cleanup.rb +32 -0
  30. data/lib/vagrant-openstack-illuin-provider/action/snapshot_delete.rb +32 -0
  31. data/lib/vagrant-openstack-illuin-provider/action/snapshot_list.rb +22 -0
  32. data/lib/vagrant-openstack-illuin-provider/action/snapshot_restore.rb +29 -0
  33. data/lib/vagrant-openstack-illuin-provider/action/snapshot_save.rb +51 -0
  34. data/lib/vagrant-openstack-illuin-provider/action/start_server.rb +24 -0
  35. data/lib/vagrant-openstack-illuin-provider/action/stop_server.rb +25 -0
  36. data/lib/vagrant-openstack-illuin-provider/action/suspend.rb +24 -0
  37. data/lib/vagrant-openstack-illuin-provider/action/sync_folders.rb +138 -0
  38. data/lib/vagrant-openstack-illuin-provider/action/wait_active.rb +33 -0
  39. data/lib/vagrant-openstack-illuin-provider/action/wait_stop.rb +33 -0
  40. data/lib/vagrant-openstack-illuin-provider/cap/snapshot_list.rb +15 -0
  41. data/lib/vagrant-openstack-illuin-provider/catalog/openstack_catalog.rb +90 -0
  42. data/lib/vagrant-openstack-illuin-provider/client/cinder.rb +39 -0
  43. data/lib/vagrant-openstack-illuin-provider/client/domain.rb +163 -0
  44. data/lib/vagrant-openstack-illuin-provider/client/glance.rb +65 -0
  45. data/lib/vagrant-openstack-illuin-provider/client/heat.rb +49 -0
  46. data/lib/vagrant-openstack-illuin-provider/client/http_utils.rb +116 -0
  47. data/lib/vagrant-openstack-illuin-provider/client/keystone.rb +128 -0
  48. data/lib/vagrant-openstack-illuin-provider/client/neutron.rb +48 -0
  49. data/lib/vagrant-openstack-illuin-provider/client/nova.rb +303 -0
  50. data/lib/vagrant-openstack-illuin-provider/client/openstack.rb +59 -0
  51. data/lib/vagrant-openstack-illuin-provider/client/request_logger.rb +23 -0
  52. data/lib/vagrant-openstack-illuin-provider/client/rest_utils.rb +28 -0
  53. data/lib/vagrant-openstack-illuin-provider/command/abstract_command.rb +51 -0
  54. data/lib/vagrant-openstack-illuin-provider/command/flavor_list.rb +24 -0
  55. data/lib/vagrant-openstack-illuin-provider/command/floatingip_list.rb +32 -0
  56. data/lib/vagrant-openstack-illuin-provider/command/image_list.rb +29 -0
  57. data/lib/vagrant-openstack-illuin-provider/command/main.rb +52 -0
  58. data/lib/vagrant-openstack-illuin-provider/command/network_list.rb +25 -0
  59. data/lib/vagrant-openstack-illuin-provider/command/openstack_command.rb +16 -0
  60. data/lib/vagrant-openstack-illuin-provider/command/reset.rb +20 -0
  61. data/lib/vagrant-openstack-illuin-provider/command/subnet_list.rb +22 -0
  62. data/lib/vagrant-openstack-illuin-provider/command/utils.rb +22 -0
  63. data/lib/vagrant-openstack-illuin-provider/command/volume_list.rb +25 -0
  64. data/lib/vagrant-openstack-illuin-provider/config.rb +505 -0
  65. data/lib/vagrant-openstack-illuin-provider/config/http.rb +39 -0
  66. data/lib/vagrant-openstack-illuin-provider/config_resolver.rb +334 -0
  67. data/lib/vagrant-openstack-illuin-provider/errors.rb +187 -0
  68. data/lib/vagrant-openstack-illuin-provider/logging.rb +39 -0
  69. data/lib/vagrant-openstack-illuin-provider/plugin.rb +58 -0
  70. data/lib/vagrant-openstack-illuin-provider/provider.rb +50 -0
  71. data/lib/vagrant-openstack-illuin-provider/utils.rb +81 -0
  72. data/lib/vagrant-openstack-illuin-provider/version.rb +15 -0
  73. data/lib/vagrant-openstack-illuin-provider/version_checker.rb +76 -0
  74. data/locales/en.yml +412 -0
  75. data/spec/vagrant-openstack-illuin-provider/action/connect_openstack_spec.rb +770 -0
  76. data/spec/vagrant-openstack-illuin-provider/action/create_server_spec.rb +260 -0
  77. data/spec/vagrant-openstack-illuin-provider/action/create_stack_spec.rb +99 -0
  78. data/spec/vagrant-openstack-illuin-provider/action/delete_server_spec.rb +89 -0
  79. data/spec/vagrant-openstack-illuin-provider/action/delete_stack_spec.rb +63 -0
  80. data/spec/vagrant-openstack-illuin-provider/action/message_spec.rb +33 -0
  81. data/spec/vagrant-openstack-illuin-provider/action/provision_spec.rb +97 -0
  82. data/spec/vagrant-openstack-illuin-provider/action/read_ssh_info_spec.rb +202 -0
  83. data/spec/vagrant-openstack-illuin-provider/action/read_state_spec.rb +81 -0
  84. data/spec/vagrant-openstack-illuin-provider/action/resume_server_spec.rb +49 -0
  85. data/spec/vagrant-openstack-illuin-provider/action/start_server_spec.rb +49 -0
  86. data/spec/vagrant-openstack-illuin-provider/action/stop_server_spec.rb +49 -0
  87. data/spec/vagrant-openstack-illuin-provider/action/suspend_server_spec.rb +49 -0
  88. data/spec/vagrant-openstack-illuin-provider/action/sync_folders_spec.rb +155 -0
  89. data/spec/vagrant-openstack-illuin-provider/action/wait_active_spec.rb +53 -0
  90. data/spec/vagrant-openstack-illuin-provider/action/wait_stop_spec.rb +53 -0
  91. data/spec/vagrant-openstack-illuin-provider/action_spec.rb +120 -0
  92. data/spec/vagrant-openstack-illuin-provider/client/cinder_spec.rb +129 -0
  93. data/spec/vagrant-openstack-illuin-provider/client/glance_spec.rb +145 -0
  94. data/spec/vagrant-openstack-illuin-provider/client/heat_spec.rb +130 -0
  95. data/spec/vagrant-openstack-illuin-provider/client/keystone_spec.rb +226 -0
  96. data/spec/vagrant-openstack-illuin-provider/client/neutron_spec.rb +173 -0
  97. data/spec/vagrant-openstack-illuin-provider/client/nova_spec.rb +760 -0
  98. data/spec/vagrant-openstack-illuin-provider/client/utils_spec.rb +176 -0
  99. data/spec/vagrant-openstack-illuin-provider/command/flavor_list_spec.rb +43 -0
  100. data/spec/vagrant-openstack-illuin-provider/command/floatingip_list_spec.rb +74 -0
  101. data/spec/vagrant-openstack-illuin-provider/command/image_list_spec.rb +95 -0
  102. data/spec/vagrant-openstack-illuin-provider/command/network_list_spec.rb +65 -0
  103. data/spec/vagrant-openstack-illuin-provider/command/reset_spec.rb +24 -0
  104. data/spec/vagrant-openstack-illuin-provider/command/subnet_list_spec.rb +45 -0
  105. data/spec/vagrant-openstack-illuin-provider/command/volume_list_spec.rb +40 -0
  106. data/spec/vagrant-openstack-illuin-provider/config_resolver_spec.rb +879 -0
  107. data/spec/vagrant-openstack-illuin-provider/config_spec.rb +416 -0
  108. data/spec/vagrant-openstack-illuin-provider/e2e_spec.rb.save +27 -0
  109. data/spec/vagrant-openstack-illuin-provider/provider_spec.rb +13 -0
  110. data/spec/vagrant-openstack-illuin-provider/spec_helper.rb +37 -0
  111. data/spec/vagrant-openstack-illuin-provider/utils_spec.rb +197 -0
  112. data/spec/vagrant-openstack-illuin-provider/version_checker_spec.rb +39 -0
  113. data/stackrc +25 -0
  114. data/vagrant-openstack-illuin-provider.gemspec +35 -0
  115. metadata +379 -0
@@ -0,0 +1,173 @@
1
+ require 'vagrant-openstack-illuin-provider/spec_helper'
2
+
3
+ describe VagrantPlugins::Openstack::NeutronClient do
4
+ let(:http) do
5
+ double('http').tap do |http|
6
+ http.stub(:read_timeout) { 42 }
7
+ http.stub(:open_timeout) { 43 }
8
+ end
9
+ end
10
+
11
+ let(:config) do
12
+ double('config').tap do |config|
13
+ config.stub(:http) { http }
14
+ config.stub(:ssl_ca_file) { nil }
15
+ config.stub(:ssl_verify_peer) { true }
16
+ end
17
+ end
18
+
19
+ let(:env) do
20
+ {}.tap do |env|
21
+ env[:machine] = double('machine')
22
+ env[:machine].stub(:provider_config) { config }
23
+ end
24
+ end
25
+
26
+ let(:session) do
27
+ VagrantPlugins::Openstack.session
28
+ end
29
+
30
+ before :each do
31
+ session.token = '123456'
32
+ session.project_id = 'a1b2c3'
33
+ session.endpoints = { network: 'http://neutron' }
34
+ @neutron_client = VagrantPlugins::Openstack.neutron
35
+ end
36
+
37
+ describe 'get_private_networks' do
38
+ context 'with token' do
39
+ it 'returns only private networks for project in session' do
40
+ stub_request(:get, 'http://neutron/networks')
41
+ .with(
42
+ headers:
43
+ {
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
+ ')
58
+
59
+ networks = @neutron_client.get_private_networks(env)
60
+
61
+ expect(networks.length).to eq(2)
62
+ expect(networks[0].id).to eq('net-1')
63
+ expect(networks[0].name).to eq('net1')
64
+ expect(networks[1].id).to eq('net-2')
65
+ expect(networks[1].name).to eq('net2')
66
+ end
67
+ end
68
+ end
69
+
70
+ describe 'get_all_networks' do
71
+ context 'with token' do
72
+ it 'returns all networks for project in session' do
73
+ stub_request(:get, 'http://neutron/networks')
74
+ .with(
75
+ headers:
76
+ {
77
+ 'Accept' => 'application/json',
78
+ 'X-Auth-Token' => '123456'
79
+ })
80
+ .to_return(
81
+ status: 200,
82
+ body: '
83
+ {
84
+ "networks": [
85
+ { "name": "PublicNetwork", "tenant_id": "admin-tenant-id", "id": "net-pub" },
86
+ { "name": "net1", "tenant_id": "a1b2c3", "id": "net-1" },
87
+ { "name": "net2", "tenant_id": "a1b2c3", "id": "net-2" }
88
+ ]
89
+ }
90
+ ')
91
+
92
+ networks = @neutron_client.get_all_networks(env)
93
+
94
+ expect(networks.length).to eq(3)
95
+ expect(networks[0].id).to eq('net-pub')
96
+ expect(networks[0].name).to eq('PublicNetwork')
97
+ expect(networks[1].id).to eq('net-1')
98
+ expect(networks[1].name).to eq('net1')
99
+ expect(networks[2].id).to eq('net-2')
100
+ expect(networks[2].name).to eq('net2')
101
+ end
102
+ end
103
+ end
104
+
105
+ describe 'get_subnets' do
106
+ context 'with token' do
107
+ it 'returns all available subnets' do
108
+ stub_request(:get, 'http://neutron/subnets')
109
+ .with(
110
+ headers:
111
+ {
112
+ 'Accept' => 'application/json',
113
+ 'X-Auth-Token' => '123456'
114
+ })
115
+ .to_return(
116
+ status: 200,
117
+ body: '
118
+ {
119
+ "subnets": [
120
+ { "id": "subnet-01", "name": "Subnet 1", "cidr": "192.168.1.0/24", "enable_dhcp": true, "network_id": "net-01" },
121
+ { "id": "subnet-02", "name": "Subnet 2", "cidr": "192.168.2.0/24", "enable_dhcp": false, "network_id": "net-01" },
122
+ { "id": "subnet-03", "name": "Subnet 3", "cidr": "192.168.100.0/24", "enable_dhcp": true, "network_id": "net-02" }
123
+ ]
124
+ }
125
+ ')
126
+
127
+ networks = @neutron_client.get_subnets(env)
128
+
129
+ expect(networks).to eq [Subnet.new('subnet-01', 'Subnet 1', '192.168.1.0/24', true, 'net-01'),
130
+ Subnet.new('subnet-02', 'Subnet 2', '192.168.2.0/24', false, 'net-01'),
131
+ Subnet.new('subnet-03', 'Subnet 3', '192.168.100.0/24', true, 'net-02')]
132
+ end
133
+ end
134
+ end
135
+
136
+ describe 'get_api_version_list' do
137
+ context 'basic' do
138
+ it 'returns version list' do
139
+ stub_request(:get, 'http://neutron/')
140
+ .with(header: { 'Accept' => 'application/json' })
141
+ .to_return(
142
+ status: 200,
143
+ body: '{
144
+ "versions": [
145
+ {
146
+ "status": "...",
147
+ "id": "v1.0",
148
+ "links": [
149
+ {
150
+ "href": "http://neutron/v1.0",
151
+ "rel": "self"
152
+ }
153
+ ]
154
+ },
155
+ {
156
+ "status": "CURRENT",
157
+ "id": "v2.0",
158
+ "links": [
159
+ {
160
+ "href": "http://neutron/v2.0",
161
+ "rel": "self"
162
+ }
163
+ ]
164
+ }
165
+ ]}')
166
+
167
+ versions = @neutron_client.get_api_version_list(env, :network)
168
+
169
+ expect(versions.size).to eq(2)
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,760 @@
1
+ require 'vagrant-openstack-illuin-provider/spec_helper'
2
+
3
+ describe VagrantPlugins::Openstack::NovaClient do
4
+ include FakeFS::SpecHelpers::All
5
+
6
+ let(:filename) { 'key.pub' }
7
+ let(:ssh_key_content) { 'my public key' }
8
+
9
+ let(:http) do
10
+ double('http').tap do |http|
11
+ http.stub(:read_timeout) { 42 }
12
+ http.stub(:open_timeout) { 43 }
13
+ end
14
+ end
15
+
16
+ let(:config) do
17
+ double('config').tap do |config|
18
+ config.stub(:openstack_auth_url) { 'http://novaAuthV2' }
19
+ config.stub(:openstack_compute_url) { nil }
20
+ config.stub(:tenant_name) { 'testTenant' }
21
+ config.stub(:username) { 'username' }
22
+ config.stub(:password) { 'password' }
23
+ config.stub(:http) { http }
24
+ config.stub(:ssl_ca_file) { nil }
25
+ config.stub(:ssl_verify_peer) { true }
26
+ end
27
+ end
28
+
29
+ let(:file) do
30
+ double('file').tap do |file|
31
+ file.stub(:read) { ssh_key_content }
32
+ end
33
+ end
34
+
35
+ let(:env) do
36
+ {}.tap do |env|
37
+ env[:ui] = double('ui')
38
+ env[:ui].stub(:info).with(anything)
39
+ env[:machine] = double('machine')
40
+ env[:machine].stub(:provider_config) { config }
41
+ end
42
+ end
43
+
44
+ let(:session) do
45
+ VagrantPlugins::Openstack.session
46
+ end
47
+
48
+ before :each do
49
+ session.token = '123456'
50
+ session.project_id = 'a1b2c3'
51
+ session.endpoints = { compute: 'http://nova/a1b2c3' }
52
+ @nova_client = VagrantPlugins::Openstack.nova
53
+ end
54
+
55
+ describe 'instance_exists' do
56
+ context 'instance not found' do
57
+ it 'raise an InstanceNotFound error' do
58
+ stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
59
+ .with(
60
+ body: '{"os-start":null}',
61
+ headers:
62
+ {
63
+ 'Accept' => 'application/json',
64
+ 'Content-Type' => 'application/json',
65
+ 'X-Auth-Token' => '123456'
66
+ })
67
+ .to_return(
68
+ status: 404,
69
+ body: '{"itemNotFound": {"message": "Instance could not be found", "code": 404}}')
70
+
71
+ expect { @nova_client.start_server(env, 'o1o2o3') }.to raise_error(VagrantPlugins::Openstack::Errors::InstanceNotFound)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'get_all_flavors' do
77
+ context 'with token and project_id acquainted' do
78
+ it 'returns all flavors' do
79
+ stub_request(:get, 'http://nova/a1b2c3/flavors/detail')
80
+ .with(
81
+ headers:
82
+ {
83
+ 'Accept' => 'application/json',
84
+ 'X-Auth-Token' => '123456'
85
+ })
86
+ .to_return(
87
+ status: 200,
88
+ body: '{
89
+ "flavors": [
90
+ { "id": "f1", "name": "flavor1", "vcpus":"1", "ram": "1024", "disk": "10"},
91
+ { "id": "f2", "name": "flavor2", "vcpus":"2", "ram": "2048", "disk": "20"}
92
+ ]}')
93
+
94
+ flavors = @nova_client.get_all_flavors(env)
95
+
96
+ expect(flavors.length).to eq(2)
97
+ expect(flavors[0]).to eq(Flavor.new('f1', 'flavor1', '1', '1024', '10'))
98
+ expect(flavors[1]).to eq(Flavor.new('f2', 'flavor2', '2', '2048', '20'))
99
+ end
100
+ end
101
+ end
102
+
103
+ describe 'get_all_images' do
104
+ context 'with token and project_id acquainted' do
105
+ it 'returns all images' do
106
+ stub_request(:get, 'http://nova/a1b2c3/images/detail')
107
+ .with(
108
+ headers:
109
+ {
110
+ 'Accept' => 'application/json',
111
+ 'X-Auth-Token' => '123456'
112
+ })
113
+ .to_return(
114
+ status: 200,
115
+ body: '{ "images": [ { "id": "i1", "name": "image1", "metadata": {"customVal1": 1}}, { "id": "i2", "name": "image2"} ] }')
116
+
117
+ images = @nova_client.get_all_images(env)
118
+
119
+ expect(images.length).to eq(2)
120
+ expect(images[0].id).to eq('i1')
121
+ expect(images[0].name).to eq('image1')
122
+ expect(images[0].metadata['customVal1']).to eq(1)
123
+ expect(images[1].id).to eq('i2')
124
+ expect(images[1].name).to eq('image2')
125
+ end
126
+ end
127
+ end
128
+
129
+ describe 'create_server' do
130
+ context 'with token and project_id acquainted' do
131
+ it 'returns new instance id' do
132
+ stub_request(:post, 'http://nova/a1b2c3/servers')
133
+ .with(
134
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key"}}',
135
+ headers:
136
+ {
137
+ 'Accept' => 'application/json',
138
+ 'Content-Type' => 'application/json',
139
+ 'X-Auth-Token' => '123456'
140
+ })
141
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
142
+
143
+ instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', networks: nil, keypair: 'key')
144
+
145
+ expect(instance_id).to eq('o1o2o3')
146
+ end
147
+
148
+ context 'with all options specified' do
149
+ it 'returns new instance id' do
150
+ stub_request(:post, 'http://nova/a1b2c3/servers')
151
+ .with(
152
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key",'\
153
+ '"security_groups":[{"name":"default"}],"user_data":"dXNlcl9kYXRhX3Rlc3Q=\n","metadata":"metadata_test"},'\
154
+ '"os:scheduler_hints":"sched_hints_test"}',
155
+ headers:
156
+ {
157
+ 'Accept' => 'application/json',
158
+ 'Content-Type' => 'application/json',
159
+ 'X-Auth-Token' => '123456'
160
+ })
161
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
162
+
163
+ instance_id = @nova_client.create_server(
164
+ env,
165
+ name: 'inst',
166
+ image_ref: 'img',
167
+ flavor_ref: 'flav',
168
+ networks: nil,
169
+ keypair: 'key',
170
+ security_groups: [{ name: 'default' }],
171
+ user_data: 'user_data_test',
172
+ metadata: 'metadata_test',
173
+ scheduler_hints: 'sched_hints_test')
174
+
175
+ expect(instance_id).to eq('o1o2o3')
176
+ end
177
+ end
178
+
179
+ context 'with two networks' do
180
+ it 'returns new instance id' do
181
+ stub_request(:post, 'http://nova/a1b2c3/servers')
182
+ .with(
183
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key","networks":[{"uuid":"net1"},{"uuid":"net2"}]}}',
184
+ headers:
185
+ {
186
+ 'Accept' => 'application/json',
187
+ 'Content-Type' => 'application/json',
188
+ 'X-Auth-Token' => '123456'
189
+ })
190
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
191
+
192
+ instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav',
193
+ networks: [{ uuid: 'net1' }, { uuid: 'net2' }], keypair: 'key')
194
+
195
+ expect(instance_id).to eq('o1o2o3')
196
+ end
197
+ end
198
+
199
+ context 'with availability_zone' do
200
+ it 'returns new instance id' do
201
+ stub_request(:post, 'http://nova/a1b2c3/servers')
202
+ .with(
203
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key","availability_zone":"avz"}}',
204
+ headers:
205
+ {
206
+ 'Accept' => 'application/json',
207
+ 'Content-Type' => 'application/json',
208
+ 'X-Auth-Token' => '123456'
209
+ })
210
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
211
+
212
+ instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', keypair: 'key', availability_zone: 'avz')
213
+
214
+ expect(instance_id).to eq('o1o2o3')
215
+ end
216
+ end
217
+
218
+ context 'with volume_boot creating volume' do
219
+ it 'create bootable volume and returns new instance id' do
220
+ stub_request(:post, 'http://nova/a1b2c3/servers')
221
+ .with(
222
+ body: '{"server":{"name":"inst","block_device_mapping_v2":[{"boot_index":"0","volume_size":"10","uuid":"image_id",'\
223
+ '"device_name":"vda","source_type":"image","destination_type":"volume","delete_on_termination":"false"}],'\
224
+ '"flavorRef":"flav","key_name":"key"}}',
225
+ 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" } }')
232
+
233
+ instance_id = @nova_client.create_server(env,
234
+ name: 'inst',
235
+ image_ref: nil,
236
+ volume_boot: { image: 'image_id', device: 'vda', size: '10',
237
+ delete_on_destroy: 'false' },
238
+ flavor_ref: 'flav',
239
+ keypair: 'key')
240
+ expect(instance_id).to eq('o1o2o3')
241
+ end
242
+ end
243
+
244
+ context 'with volume_boot id' do
245
+ it 'returns new instance id' do
246
+ stub_request(:post, 'http://nova/a1b2c3/servers')
247
+ .with(
248
+ body: '{"server":{"name":"inst","block_device_mapping":[{"volume_id":"vol","device_name":"vda"}],'\
249
+ '"flavorRef":"flav","key_name":"key"}}',
250
+ headers:
251
+ {
252
+ 'Accept' => 'application/json',
253
+ 'Content-Type' => 'application/json',
254
+ 'X-Auth-Token' => '123456'
255
+ })
256
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
257
+
258
+ instance_id = @nova_client.create_server(env,
259
+ name: 'inst',
260
+ volume_boot: { id: 'vol', device: 'vda' },
261
+ flavor_ref: 'flav',
262
+ keypair: 'key')
263
+ expect(instance_id).to eq('o1o2o3')
264
+ end
265
+ end
266
+ end
267
+ end
268
+
269
+ describe 'delete_server' do
270
+ context 'with token and project_id acquainted' do
271
+ it 'returns new instance id' do
272
+ stub_request(:delete, 'http://nova/a1b2c3/servers/o1o2o3')
273
+ .with(
274
+ headers: {
275
+ 'Accept' => 'application/json',
276
+ 'X-Auth-Token' => '123456'
277
+ })
278
+ .to_return(status: 204)
279
+
280
+ @nova_client.delete_server(env, 'o1o2o3')
281
+ end
282
+ end
283
+ end
284
+
285
+ describe 'import_keypair_from_file' do
286
+ context 'with token and project_id acquainted' do
287
+ it 'returns newly created keypair name' do
288
+ File.should_receive(:exist?).with(filename).and_return(true)
289
+ File.should_receive(:open).with(filename).and_return(file)
290
+ Kernel.stub(:rand).and_return(2_036_069_739_008)
291
+
292
+ stub_request(:post, 'http://nova/a1b2c3/os-keypairs')
293
+ .with(
294
+ body: "{\"keypair\":{\"name\":\"vagrant-generated-pzcvcpa8\",\"public_key\":\"#{ssh_key_content}\"}}",
295
+ headers: {
296
+ 'Accept' => 'application/json',
297
+ 'Content-Type' => 'application/json',
298
+ 'X-Auth-Token' => '123456' })
299
+ .to_return(status: 200, body: '
300
+ {
301
+ "keypair": {
302
+ "name": "created_key_name"
303
+ }
304
+ }')
305
+
306
+ @nova_client.import_keypair_from_file(env, filename)
307
+ end
308
+ end
309
+ end
310
+
311
+ describe 'delete_keypair_if_vagrant' do
312
+ context 'with token and project_id acquainted' do
313
+ context 'with keypair not generated by vagrant' do
314
+ it 'do nothing' do
315
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
316
+ .with(headers:
317
+ {
318
+ 'Accept' => 'application/json',
319
+ 'X-Auth-Token' => '123456'
320
+ })
321
+ .to_return(status: 200, body: '
322
+ {
323
+ "server": {
324
+ "id": "o1o2o3",
325
+ "key_name": "other_key"
326
+ }
327
+ }
328
+ ')
329
+
330
+ @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
331
+ end
332
+ end
333
+ context 'with keypair generated by vagrant' do
334
+ it 'deletes the key on nova' do
335
+ stub_request(:delete, 'http://nova/a1b2c3/os-keypairs/vagrant-generated-1234')
336
+ .with(headers: { 'X-Auth-Token' => '123456' })
337
+ .to_return(status: 202)
338
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
339
+ .with(headers:
340
+ {
341
+ 'Accept' => 'application/json',
342
+ 'X-Auth-Token' => '123456'
343
+ })
344
+ .to_return(status: 200, body: '
345
+ {
346
+ "server": {
347
+ "id": "o1o2o3",
348
+ "key_name": "vagrant-generated-1234"
349
+ }
350
+ }
351
+ ')
352
+
353
+ @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
354
+ end
355
+ end
356
+ context 'with keypair generated by vagrant and missing in server details' do
357
+ it 'do nothing' do
358
+ stub_request(:delete, 'http://nova/a1b2c3/os-keypairs/vagrant-generated-1234')
359
+ .with(headers: { 'X-Auth-Token' => '123456' })
360
+ .to_return(status: 202)
361
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
362
+ .with(headers:
363
+ {
364
+ 'Accept' => 'application/json',
365
+ 'X-Auth-Token' => '123456'
366
+ })
367
+ .to_return(status: 200, body: '
368
+ {
369
+ "server": {
370
+ "id": "o1o2o3"
371
+ }
372
+ }
373
+ ')
374
+
375
+ @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
376
+ end
377
+ end
378
+ end
379
+ end
380
+
381
+ describe 'suspend_server' do
382
+ context 'with token and project_id acquainted' do
383
+ it 'returns new instance id' do
384
+ stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
385
+ .with(
386
+ body: '{"suspend":null}',
387
+ headers:
388
+ {
389
+ 'Accept' => 'application/json',
390
+ 'Content-Type' => 'application/json',
391
+ 'X-Auth-Token' => '123456'
392
+ })
393
+ .to_return(status: 202)
394
+
395
+ @nova_client.suspend_server(env, 'o1o2o3')
396
+ end
397
+ end
398
+ end
399
+
400
+ describe 'resume_server' do
401
+ context 'with token and project_id acquainted' do
402
+ it 'returns new instance id' do
403
+ stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
404
+ .with(
405
+ body: '{"resume":null}',
406
+ headers:
407
+ {
408
+ 'Accept' => 'application/json',
409
+ 'Content-Type' => 'application/json',
410
+ 'X-Auth-Token' => '123456'
411
+ })
412
+ .to_return(status: 202)
413
+
414
+ @nova_client.resume_server(env, 'o1o2o3')
415
+ end
416
+ end
417
+ end
418
+
419
+ describe 'stop_server' do
420
+ context 'with token and project_id acquainted' do
421
+ it 'returns new instance id' do
422
+ stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
423
+ .with(
424
+ body: '{"os-stop":null}',
425
+ headers:
426
+ {
427
+ 'Accept' => 'application/json',
428
+ 'Content-Type' => 'application/json',
429
+ 'X-Auth-Token' => '123456'
430
+ })
431
+ .to_return(status: 202)
432
+
433
+ @nova_client.stop_server(env, 'o1o2o3')
434
+ end
435
+ end
436
+ end
437
+
438
+ describe 'start_server' do
439
+ context 'with token and project_id acquainted' do
440
+ it 'returns new instance id' do
441
+ stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
442
+ .with(
443
+ body: '{"os-start":null}',
444
+ headers:
445
+ {
446
+ 'Accept' => 'application/json',
447
+ 'Content-Type' => 'application/json',
448
+ 'X-Auth-Token' => '123456'
449
+ })
450
+ .to_return(status: 202)
451
+
452
+ @nova_client.start_server(env, 'o1o2o3')
453
+ end
454
+ end
455
+ end
456
+
457
+ describe 'get_all_floating_ips' do
458
+ context 'with token and project_id acquainted' do
459
+ it 'returns all floating ips' do
460
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
461
+ .with(headers:
462
+ {
463
+ 'Accept' => 'application/json',
464
+ 'Accept-Encoding' => 'gzip, deflate',
465
+ 'User-Agent' => /.*/,
466
+ 'X-Auth-Token' => '123456'
467
+ })
468
+ .to_return(status: 200, body: '
469
+ {
470
+ "floating_ips": [
471
+ {"instance_id": "1234",
472
+ "ip": "185.39.216.45",
473
+ "fixed_ip": "192.168.0.54",
474
+ "id": "2345",
475
+ "pool": "PublicNetwork-01"
476
+ },
477
+ {
478
+ "instance_id": null,
479
+ "ip": "185.39.216.95",
480
+ "fixed_ip": null,
481
+ "id": "3456",
482
+ "pool": "PublicNetwork-02"
483
+ }]
484
+ }')
485
+
486
+ floating_ips = @nova_client.get_all_floating_ips(env)
487
+
488
+ expect(floating_ips).not_to be_nil
489
+ expect(floating_ips.size).to eq(2)
490
+ expect(floating_ips[0].ip).to eql('185.39.216.45')
491
+ expect(floating_ips[0].instance_id).to eql('1234')
492
+ expect(floating_ips[0].pool).to eql('PublicNetwork-01')
493
+ expect(floating_ips[1].ip).to eql('185.39.216.95')
494
+ expect(floating_ips[1].instance_id).to be(nil)
495
+ expect(floating_ips[1].pool).to eql('PublicNetwork-02')
496
+ end
497
+ end
498
+ end
499
+
500
+ describe 'get_all_floating_ips' do
501
+ context 'with token and project_id acquainted' do
502
+ it 'return newly allocated floating_ip' do
503
+ stub_request(:post, 'http://nova/a1b2c3/os-floating-ips')
504
+ .with(body: '{"pool":"pool-1"}',
505
+ headers: {
506
+ 'Accept' => 'application/json',
507
+ 'Content-Type' => 'application/json',
508
+ 'X-Auth-Token' => '123456' })
509
+ .to_return(status: 200, body: '
510
+ {
511
+ "floating_ip": {
512
+ "instance_id": null,
513
+ "ip": "183.45.67.89",
514
+ "fixed_ip": null,
515
+ "id": "o1o2o3",
516
+ "pool": "pool-1"
517
+ }
518
+ }')
519
+ floating_ip = @nova_client.allocate_floating_ip(env, 'pool-1')
520
+
521
+ expect(floating_ip.ip).to eql('183.45.67.89')
522
+ expect(floating_ip.instance_id).to be(nil)
523
+ expect(floating_ip.pool).to eql('pool-1')
524
+ end
525
+ end
526
+ end
527
+
528
+ describe 'get_server_details' do
529
+ context 'with token and project_id acquainted' do
530
+ it 'returns server details' do
531
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
532
+ .with(headers:
533
+ {
534
+ 'Accept' => 'application/json',
535
+ 'X-Auth-Token' => '123456'
536
+ })
537
+ .to_return(status: 200, body: '
538
+ {
539
+ "server": {
540
+ "addresses": { "private": [ { "addr": "192.168.0.3", "version": 4 } ] },
541
+ "created": "2012-08-20T21:11:09Z",
542
+ "flavor": { "id": "1" },
543
+ "id": "o1o2o3",
544
+ "image": { "id": "i1" },
545
+ "name": "new-server-test",
546
+ "progress": 0,
547
+ "status": "ACTIVE",
548
+ "tenant_id": "openstack",
549
+ "updated": "2012-08-20T21:11:09Z",
550
+ "user_id": "fake"
551
+ }
552
+ }
553
+ ')
554
+
555
+ server = @nova_client.get_server_details(env, 'o1o2o3')
556
+
557
+ expect(server['id']).to eq('o1o2o3')
558
+ expect(server['status']).to eq('ACTIVE')
559
+ expect(server['tenant_id']).to eq('openstack')
560
+ expect(server['image']['id']).to eq('i1')
561
+ expect(server['flavor']['id']).to eq('1')
562
+ end
563
+ end
564
+ end
565
+
566
+ describe 'add_floating_ip' do
567
+ context 'with token and project_id acquainted and IP available' do
568
+ it 'returns server details' do
569
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
570
+ .with(headers:
571
+ {
572
+ 'Accept' => 'application/json',
573
+ 'X-Auth-Token' => '123456'
574
+ })
575
+ .to_return(status: 200, body: '
576
+ {
577
+ "floating_ips": [
578
+ {
579
+ "fixed_ip": null,
580
+ "id": 1,
581
+ "instance_id": null,
582
+ "ip": "1.2.3.4",
583
+ "pool": "nova"
584
+ },
585
+ {
586
+ "fixed_ip": null,
587
+ "id": 2,
588
+ "instance_id": null,
589
+ "ip": "5.6.7.8",
590
+ "pool": "nova"
591
+ }
592
+ ]
593
+ }')
594
+
595
+ stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
596
+ .with(body: '{"addFloatingIp":{"address":"1.2.3.4"}}',
597
+ headers:
598
+ {
599
+ 'Accept' => 'application/json',
600
+ 'Content-Type' => 'application/json',
601
+ 'X-Auth-Token' => '123456'
602
+ })
603
+ .to_return(status: 202)
604
+
605
+ @nova_client.add_floating_ip(env, 'o1o2o3', '1.2.3.4')
606
+ end
607
+ end
608
+
609
+ context 'with token and project_id acquainted and IP already in use' do
610
+ it 'raise an error' do
611
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
612
+ .with(headers:
613
+ {
614
+ 'Accept' => 'application/json',
615
+ 'X-Auth-Token' => '123456'
616
+ })
617
+ .to_return(status: 200, body: '
618
+ {
619
+ "floating_ips": [
620
+ {
621
+ "fixed_ip": null,
622
+ "id": 1,
623
+ "instance_id": "inst",
624
+ "ip": "1.2.3.4",
625
+ "pool": "nova"
626
+ },
627
+ {
628
+ "fixed_ip": null,
629
+ "id": 2,
630
+ "instance_id": null,
631
+ "ip": "5.6.7.8",
632
+ "pool": "nova"
633
+ }
634
+ ]
635
+ }')
636
+
637
+ expect { @nova_client.add_floating_ip(env, 'o1o2o3', '1.2.3.4') }.to raise_error(Errors::FloatingIPAlreadyAssigned)
638
+ end
639
+ end
640
+
641
+ context 'with token and project_id acquainted and IP not allocated' do
642
+ it 'raise an error' do
643
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
644
+ .with(headers:
645
+ {
646
+ 'Accept' => 'application/json',
647
+ 'X-Auth-Token' => '123456'
648
+ })
649
+ .to_return(status: 200, body: '
650
+ {
651
+ "floating_ips": [
652
+ {
653
+ "fixed_ip": null,
654
+ "id": 2,
655
+ "instance_id": null,
656
+ "ip": "5.6.7.8",
657
+ "pool": "nova"
658
+ }
659
+ ]
660
+ }')
661
+
662
+ expect { @nova_client.add_floating_ip(env, 'o1o2o3', '1.2.3.4') }.to raise_error(Errors::FloatingIPNotAvailable)
663
+ end
664
+ end
665
+ end
666
+
667
+ describe 'get_floating_ip_pools' do
668
+ context 'with token and project_id acquainted' do
669
+ it 'should return floating ip pool' do
670
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ip-pools')
671
+ .with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => '123456' })
672
+ .to_return(status: 200, body: '
673
+ {
674
+ "floating_ip_pools": [
675
+ {
676
+ "name": "pool1"
677
+ },
678
+ {
679
+ "name": "pool2"
680
+ }
681
+ ]
682
+ }
683
+ ')
684
+
685
+ pools = @nova_client.get_floating_ip_pools(env)
686
+
687
+ expect(pools[0]['name']).to eq('pool1')
688
+ expect(pools[1]['name']).to eq('pool2')
689
+ end
690
+ end
691
+ end
692
+
693
+ describe 'get_floating_ips' do
694
+ context 'with token and project_id acquainted' do
695
+ it 'should return floating ip list' do
696
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
697
+ .with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => '123456' })
698
+ .to_return(status: 200, body: '
699
+ {
700
+ "floating_ips": [
701
+ {
702
+ "fixed_ip": null,
703
+ "id": 1,
704
+ "instance_id": null,
705
+ "ip": "10.10.10.1",
706
+ "pool": "pool1"
707
+ },
708
+ {
709
+ "fixed_ip": null,
710
+ "id": 2,
711
+ "instance_id": "inst001",
712
+ "ip": "10.10.10.2",
713
+ "pool": "pool2"
714
+ }
715
+ ]
716
+ }
717
+ ')
718
+
719
+ ips = @nova_client.get_floating_ips(env)
720
+
721
+ expect(ips[0]['ip']).to eq('10.10.10.1')
722
+ expect(ips[0]['instance_id']).to eq(nil)
723
+ expect(ips[0]['pool']).to eq('pool1')
724
+
725
+ expect(ips[1]['ip']).to eq('10.10.10.2')
726
+ expect(ips[1]['instance_id']).to eq('inst001')
727
+ expect(ips[1]['pool']).to eq('pool2')
728
+ end
729
+ end
730
+ end
731
+
732
+ describe 'attach_volume' do
733
+ context 'with token and project_id acquainted' do
734
+ context 'with volume id and device' do
735
+ it 'call the nova api' do
736
+ stub_request(:post, 'http://nova/a1b2c3/servers/9876/os-volume_attachments')
737
+ .with(headers:
738
+ {
739
+ 'Accept' => 'application/json',
740
+ 'X-Auth-Token' => '123456'
741
+ },
742
+ body: '{"volumeAttachment":{"volumeId":"n1n2","device":"/dev/vdg"}}')
743
+ .to_return(status: 200, body: '
744
+ {
745
+ "volumeAttachment": {
746
+ "device": "/dev/vdg",
747
+ "id": "attachment-01",
748
+ "serverId": "9876",
749
+ "volumeId": "n1n2"
750
+ }
751
+ }
752
+ ')
753
+
754
+ attachment = @nova_client.attach_volume(env, '9876', 'n1n2', '/dev/vdg')
755
+ expect(attachment['id']).to eq('attachment-01')
756
+ end
757
+ end
758
+ end
759
+ end
760
+ end