kitchen-cloudstack 0.9.2 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20f6e6e8215c1e0ce64e7d5a78798c8e9c1135bc
4
- data.tar.gz: 3babb8874f9944d489efe6b994fbcd8d793d73b2
3
+ metadata.gz: c8040fde05ddb78c105dcde532e513609778f21c
4
+ data.tar.gz: 4026c35590d771c985f69282d31a0913af1e46f5
5
5
  SHA512:
6
- metadata.gz: 6bfcc0b18e01c7227aeafda51a83ab3ae91465c945affb7f8c9f5b6d38d590f78f0bf430aa9c5e5b33f74c629fedb4b0d7755926611766433cb9dc3570d38972
7
- data.tar.gz: 07afdce65f0cf8652e63e3d116eeadf9ef8f3c45e064613df36dcd71615777cd2fa37ac3b6d28afebfe3c8255de9d4f5c8fcc6ca20b6290193c6deb41870affd
6
+ metadata.gz: eb0259abafb6e674cec30e039d5b21c381f53ce04a1f19969791c9ee23becce992d4d0764faad15bf9e9b73e4abd110bc38d124b097ede7fcd21380b08220e4a
7
+ data.tar.gz: e0a1d0c94393570a6b8d487fc0f357297af5cc82a9140a6679d767081a20bc2e72c1ac4697d9aa1376e493ba4db7274acba37603a4fca8aa284e8ff7f08a00e7
data/README.md CHANGED
@@ -24,6 +24,7 @@ Provide, at a minimum, the required driver options in your `.kitchen.yml` file:
24
24
  OPTIONAL
25
25
  cloudstack_sync_time: [NUMBER OF SECONDS TO WAIT FOR CLOUD-SET-GUEST-PASSWORD/SSHKEY]
26
26
  keypair_search_directory: [PATH TO DIRECTORY (other than ~, ., and ~/.ssh) WITH KEYPAIR PEM FILE]
27
+ cloudstack_vm_public_ip: [PUBLIC_IP] # In case you use advanced networking and do static NAT manually.
27
28
 
28
29
  Then to specify different OS templates,
29
30
 
@@ -40,7 +41,8 @@ To use the CloudStack public key provider, you need to have the .PEM file locate
40
41
  your .kitchen.yml file, your home directory (~), your .ssh directory (~/.ssh/), or specify a directory (without any
41
42
  trailing slahses) as your "keypair_search_directory" and the file be named the same as the Keypair on CloudStack
42
43
  suffixed with .pem (e.g. the Keypair named "TestKey" should be located in one of the searched directories and named
43
- "TestKey.pem").
44
+ "TestKey.pem").
45
+ This PEM file should be the PRIVATE key, not the PUBLIC key.
44
46
 
45
47
  By default, a unique server name will be generated and the randomly generated password will be used, though that
46
48
  behavior can be overridden with additional options (e.g., to specify a SSH private key):
@@ -96,8 +98,8 @@ Apache 2.0 (see [LICENSE][license])
96
98
 
97
99
 
98
100
  [author]: https://github.com/fifthecho
99
- [issues]: https://github.com/fifthecho/kitchen-cloudstack/issues
100
- [license]: https://github.com/fifthecho/kitchen-cloudstack/blob/master/LICENSE
101
- [repo]: https://github.com/fifthecho/kitchen-cloudstack
101
+ [issues]: https://github.com/test-kitchen/kitchen-cloudstack/issues
102
+ [license]: https://github.com/test-kitchen/kitchen-cloudstack/blob/master/LICENSE
103
+ [repo]: https://github.com/test-kitchen/kitchen-cloudstack
102
104
  [driver_usage]: http://docs.kitchen-ci.org/drivers/usage
103
- [chef_omnibus_dl]: http://www.opscode.com/chef/install/
105
+ [chef_omnibus_dl]: http://getchef.com/chef/install/
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Kitchen::Driver::CLOUDSTACK_VERSION
9
9
  spec.authors = ['Jeff Moody']
10
10
  spec.email = ['fifthecho@gmail.com']
11
- spec.description = %q{A Test Kitchen Driver for Cloudstack}
12
- spec.summary = spec.description
13
- spec.homepage = 'https://github.com/fifthecho/kitchen-cloudstack'
11
+ spec.description = %q{A Test Kitchen Driver for Apache CloudStack}
12
+ spec.summary = %q{Provides an interface for Test Kitchen to be able to run jobs against an Apache CloudStack cloud.}
13
+ spec.homepage = 'https://github.com/test-kitchen/kitchen-cloudstack'
14
14
  spec.license = 'Apache 2.0'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -18,15 +18,14 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'test-kitchen', '>= 1.0.0'
22
- spec.add_dependency 'fog', ">=1.15.0"
23
- spec.add_dependency 'net-ssh-multi'
21
+ spec.add_dependency 'test-kitchen', '~> 1.0', '>= 1.0.0'
22
+ spec.add_dependency 'fog', '~> 1.23', '>= 1.23.0'
24
23
 
25
24
  spec.add_development_dependency 'bundler', '~> 1.3'
26
- spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rake', '~> 0'
27
26
 
28
- spec.add_development_dependency 'cane'
29
- spec.add_development_dependency 'tailor'
30
- spec.add_development_dependency 'countloc'
31
- spec.add_development_dependency 'pry'
27
+ spec.add_development_dependency 'cane', '~> 0'
28
+ spec.add_development_dependency 'tailor', '~> 0'
29
+ spec.add_development_dependency 'countloc', '~> 0'
30
+ spec.add_development_dependency 'pry', '~> 0'
32
31
  end
@@ -20,7 +20,7 @@ require 'benchmark'
20
20
  require 'kitchen'
21
21
  require 'fog'
22
22
  require 'socket'
23
- require 'net/ssh/multi'
23
+ require 'openssl'
24
24
  # require 'pry'
25
25
 
26
26
  module Kitchen
@@ -51,10 +51,7 @@ module Kitchen
51
51
  def create_server
52
52
  options = {}
53
53
  config[:server_name] ||= generate_name(instance.name)
54
- options['zoneid'] = config[:cloudstack_zone_id]
55
- options['templateid'] = config[:cloudstack_template_id]
56
54
  options['displayname'] = config[:server_name]
57
- options['serviceofferingid'] = config[:cloudstack_serviceoffering_id]
58
55
  if (!config[:cloudstack_network_id].nil?)
59
56
  options['networkids'] = config[:cloudstack_network_id]
60
57
  end
@@ -69,7 +66,8 @@ module Kitchen
69
66
 
70
67
  debug(options)
71
68
  # binding.pry
72
- compute.deploy_virtual_machine(options)
69
+ compute.deploy_virtual_machine(config[:cloudstack_serviceoffering_id],
70
+ config[:cloudstack_template_id], config[:cloudstack_zone_id], options)
73
71
  end
74
72
 
75
73
  def create(state)
@@ -83,6 +81,7 @@ module Kitchen
83
81
  Excon.defaults[:ssl_verify_peer] = false
84
82
  end
85
83
 
84
+
86
85
  server = create_server
87
86
  debug(server)
88
87
 
@@ -91,11 +90,11 @@ module Kitchen
91
90
  info("CloudStack instance <#{state[:server_id]}> created.")
92
91
  debug("Job ID #{jobid}")
93
92
 
94
- server_start = compute.query_async_job_result('jobid'=>jobid)
93
+ server_start = compute.query_async_job_result(jobid)
95
94
  while server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 0
96
95
  print ". "
97
96
  sleep(10)
98
- server_start = compute.query_async_job_result('jobid'=>jobid)
97
+ server_start = compute.query_async_job_result(jobid)
99
98
  end
100
99
  debug("Server_Start: #{server_start} \n")
101
100
 
@@ -114,41 +113,50 @@ module Kitchen
114
113
  password = nil
115
114
  if ((!config[:keypair_search_directory].nil?) and (File.exist?("#{config[:keypair_search_directory]}/#{config[:cloudstack_ssh_keypair_name]}.pem")))
116
115
  keypair = "#{config[:keypair_search_directory]}/#{config[:cloudstack_ssh_keypair_name]}.pem"
116
+ debug("Keypair being used is #{keypair}")
117
117
  elsif File.exist?("./#{config[:cloudstack_ssh_keypair_name]}.pem")
118
118
  keypair = "./#{config[:cloudstack_ssh_keypair_name]}.pem"
119
- elsif File.exist?("~/#{config[:cloudstack_ssh_keypair_name]}.pem")
120
- keypair = "~/#{config[:cloudstack_ssh_keypair_name]}.pem"
121
- elsif File.exist?("~/.ssh/#{config[:cloudstack_ssh_keypair_name]}.pem")
122
- keypair = "~/.ssh/#{config[:cloudstack_ssh_keypair_name]}.pem"
119
+ debug("Keypair being used is #{keypair}")
120
+ elsif File.exist?("#{ENV["HOME"]}/#{config[:cloudstack_ssh_keypair_name]}.pem")
121
+ keypair = "#{ENV["HOME"]}/#{config[:cloudstack_ssh_keypair_name]}.pem"
122
+ debug("Keypair being used is #{keypair}")
123
+ elsif File.exist?("#{ENV["HOME"]}/.ssh/#{config[:cloudstack_ssh_keypair_name]}.pem")
124
+ keypair = "#{ENV["HOME"]}/.ssh/#{config[:cloudstack_ssh_keypair_name]}.pem"
125
+ debug("Keypair being used is #{keypair}")
123
126
  elsif (!config[:cloudstack_ssh_keypair_name].nil?)
124
127
  info("Keypair specified but not found. Using password if enabled.")
125
128
  end
126
129
 
130
+ # binding.pry
127
131
  # debug("Keypair is #{keypair}")
128
- state[:hostname] = server_info.fetch('nic').first.fetch('ipaddress')
129
- tcp_test_ssh(state[:hostname])
132
+ state[:hostname] = config[:cloudstack_vm_public_ip] || server_info.fetch('nic').first.fetch('ipaddress')
133
+ wait_for_sshd(state[:hostname])
134
+
130
135
  debug("SSH Connectivity Validated.")
131
136
 
132
137
  if (!keypair.nil?)
133
138
  debug("Using keypair: #{keypair}")
134
139
  info("SSH for #{state[:hostname]} with keypair #{config[:cloudstack_ssh_keypair_name]}.")
140
+ ssh_key = File.read(keypair)
141
+ if ssh_key.split[0] == "ssh-rsa" or ssh_key.split[0] == "ssh-dsa"
142
+ error("SSH key #{keypair} is not a Private Key. Please modify your .kitchen.yml")
143
+ end
135
144
  ssh = Fog::SSH.new(state[:hostname], config[:username], {:keys => keypair})
136
- debug(state[:hostname])
137
- debug(config[:username])
138
- debug(keypair)
139
- deploy_private_key(state[:hostname], ssh)
145
+ debug("Connecting to : #{state[:hostname]} as #{config[:username]} using keypair #{keypair}.")
140
146
  elsif (server_info.fetch('passwordenabled') == true)
141
147
  password = server_info.fetch('password')
142
148
  # Print out IP and password so you can record it if you want.
143
149
  info("Password for #{config[:username]} at #{state[:hostname]} is #{password}")
144
150
  ssh = Fog::SSH.new(state[:hostname], config[:username], {:password => password})
145
- debug(state[:hostname])
146
- debug(config[:username])
147
- debug(password)
148
- deploy_private_key(state[:hostname], ssh)
151
+ debug("Connecting to : #{state[:hostname]} as #{config[:username]} using password #{password}.")
149
152
  else
150
153
  info("No keypair specified (or file not found) nor is this a password enabled template. You will have to manually copy your SSH public key to #{state[:hostname]} to use this Kitchen.")
151
154
  end
155
+ # binding.pry
156
+
157
+ validate_ssh_connectivity(ssh)
158
+
159
+ deploy_private_key(ssh)
152
160
  end
153
161
  end
154
162
 
@@ -156,62 +164,65 @@ module Kitchen
156
164
  return if state[:server_id].nil?
157
165
 
158
166
  server = compute.servers.get(state[:server_id])
159
- server.destroy unless server.nil?
167
+ compute.destroy_virtual_machine(state[:server_id]) unless server.nil?
160
168
  info("CloudStack instance <#{state[:server_id]}> destroyed.")
161
169
  state.delete(:server_id)
162
170
  state.delete(:hostname)
163
171
  end
164
172
 
165
- def tcp_test_ssh(hostname)
166
- # Ripped unceremoniously from knife-cloudstack-fog as I was having issues with the wait_for_sshd() function.
167
- print(". ")
168
- tcp_socket = TCPSocket.new(hostname, 22)
169
- readable = IO.select([tcp_socket], nil, nil, 5)
170
- if readable
171
- debug("\nsshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}\n")
172
- true
173
- else
173
+ def validate_ssh_connectivity(ssh)
174
+ rescue Errno::ETIMEDOUT
175
+ debug("SSH connection timed out. Retrying.")
176
+ sleep 2
174
177
  false
175
- end
176
-
177
- rescue Errno::ETIMEDOUT
178
- sleep 2
179
- false
180
- rescue Errno::EPERM
181
- false
182
- rescue Errno::ECONNREFUSED
183
- sleep 2
184
- false
185
- rescue Errno::EHOSTUNREACH
186
- sleep 2
187
- false
188
- rescue Errno::ENETUNREACH
189
- sleep 30
190
- false
191
- rescue Net::SSH::Disconnect
192
- sleep 15
193
- false
194
- ensure
195
- tcp_socket && tcp_socket.close
178
+ rescue Errno::EPERM
179
+ debug("SSH connection returned error. Retrying.")
180
+ false
181
+ rescue Errno::ECONNREFUSED
182
+ debug("SSH connection returned connection refused. Retrying.")
183
+ sleep 2
184
+ false
185
+ rescue Errno::EHOSTUNREACH
186
+ debug("SSH connection returned host unreachable. Retrying.")
187
+ sleep 2
188
+ false
189
+ rescue Errno::ENETUNREACH
190
+ debug("SSH connection returned network unreachable. Retrying.")
191
+ sleep 30
192
+ false
193
+ rescue Net::SSH::Disconnect
194
+ debug("SSH connection has been disconnected. Retrying.")
195
+ sleep 15
196
+ false
197
+ rescue Net::SSH::AuthenticationFailed
198
+ debug("SSH authentication has failed. Password or Keys may not be in place yet. Retrying.")
199
+ sleep 15
200
+ false
201
+ ensure
202
+ sync_time = 45
203
+ if (config[:cloudstack_sync_time])
204
+ sync_time = config[:cloudstack_sync_time]
205
+ end
206
+ sleep(sync_time)
207
+ debug("Connecting to host and running ls")
208
+ ssh.run('ls')
196
209
  end
197
210
 
198
- def deploy_private_key(hostname, ssh)
199
- debug("Deploying private key to #{hostname} using connection #{ssh}")
200
- tcp_test_ssh(hostname)
201
- sync_time = 45
202
- if (config[:cloudstack_sync_time])
203
- sync_time = config[:cloudstack_sync_time]
211
+ def deploy_private_key(ssh)
212
+ debug("Deploying user private key to server using connection #{ssh} to guarantee connectivity.")
213
+ if File.exist?("#{ENV["HOME"]}/.ssh/id_rsa.pub")
214
+ user_public_key = File.read("#{ENV["HOME"]}/.ssh/id_rsa.pub")
215
+ elsif File.exist?("#{ENV["HOME"]}/.ssh/id_dsa.pub")
216
+ user_public_key = File.read("#{ENV["HOME"]}/.ssh/id_dsa.pub")
217
+ else
218
+ debug("No public SSH key for user. Skipping.")
204
219
  end
205
- debug("Sync time is #{sync_time}")
206
- if !(config[:public_key_path].nil?)
207
- pub_key = open(config[:public_key_path]).read
208
- # Wait a few moments for the OS to run the cloud-setup-password scripts
209
- sleep(sync_time)
220
+
221
+ if user_public_key
210
222
  ssh.run([
211
223
  %{mkdir .ssh},
212
- %{echo "#{pub_key}" >> ~/.ssh/authorized_keys}
224
+ %{echo "#{user_public_key}" >> ~/.ssh/authorized_keys}
213
225
  ])
214
-
215
226
  end
216
227
  end
217
228
 
@@ -21,6 +21,6 @@ module Kitchen
21
21
  module Driver
22
22
 
23
23
  # Version string for Cloudstack Kitchen driver
24
- CLOUDSTACK_VERSION = "0.9.2"
24
+ CLOUDSTACK_VERSION = "0.10.0"
25
25
  end
26
26
  end
metadata CHANGED
@@ -1,19 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-cloudstack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Moody
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-06 00:00:00.000000000 Z
11
+ date: 2014-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-kitchen
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
17
20
  - - ">="
18
21
  - !ruby/object:Gem::Version
19
22
  version: 1.0.0
@@ -21,6 +24,9 @@ dependencies:
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
24
30
  - - ">="
25
31
  - !ruby/object:Gem::Version
26
32
  version: 1.0.0
@@ -28,30 +34,22 @@ dependencies:
28
34
  name: fog
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.15.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
37
+ - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: 1.15.0
41
- - !ruby/object:Gem::Dependency
42
- name: net-ssh-multi
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
39
+ version: '1.23'
45
40
  - - ">="
46
41
  - !ruby/object:Gem::Version
47
- version: '0'
42
+ version: 1.23.0
48
43
  type: :runtime
49
44
  prerelease: false
50
45
  version_requirements: !ruby/object:Gem::Requirement
51
46
  requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.23'
52
50
  - - ">="
53
51
  - !ruby/object:Gem::Version
54
- version: '0'
52
+ version: 1.23.0
55
53
  - !ruby/object:Gem::Dependency
56
54
  name: bundler
57
55
  requirement: !ruby/object:Gem::Requirement
@@ -70,73 +68,73 @@ dependencies:
70
68
  name: rake
71
69
  requirement: !ruby/object:Gem::Requirement
72
70
  requirements:
73
- - - ">="
71
+ - - "~>"
74
72
  - !ruby/object:Gem::Version
75
73
  version: '0'
76
74
  type: :development
77
75
  prerelease: false
78
76
  version_requirements: !ruby/object:Gem::Requirement
79
77
  requirements:
80
- - - ">="
78
+ - - "~>"
81
79
  - !ruby/object:Gem::Version
82
80
  version: '0'
83
81
  - !ruby/object:Gem::Dependency
84
82
  name: cane
85
83
  requirement: !ruby/object:Gem::Requirement
86
84
  requirements:
87
- - - ">="
85
+ - - "~>"
88
86
  - !ruby/object:Gem::Version
89
87
  version: '0'
90
88
  type: :development
91
89
  prerelease: false
92
90
  version_requirements: !ruby/object:Gem::Requirement
93
91
  requirements:
94
- - - ">="
92
+ - - "~>"
95
93
  - !ruby/object:Gem::Version
96
94
  version: '0'
97
95
  - !ruby/object:Gem::Dependency
98
96
  name: tailor
99
97
  requirement: !ruby/object:Gem::Requirement
100
98
  requirements:
101
- - - ">="
99
+ - - "~>"
102
100
  - !ruby/object:Gem::Version
103
101
  version: '0'
104
102
  type: :development
105
103
  prerelease: false
106
104
  version_requirements: !ruby/object:Gem::Requirement
107
105
  requirements:
108
- - - ">="
106
+ - - "~>"
109
107
  - !ruby/object:Gem::Version
110
108
  version: '0'
111
109
  - !ruby/object:Gem::Dependency
112
110
  name: countloc
113
111
  requirement: !ruby/object:Gem::Requirement
114
112
  requirements:
115
- - - ">="
113
+ - - "~>"
116
114
  - !ruby/object:Gem::Version
117
115
  version: '0'
118
116
  type: :development
119
117
  prerelease: false
120
118
  version_requirements: !ruby/object:Gem::Requirement
121
119
  requirements:
122
- - - ">="
120
+ - - "~>"
123
121
  - !ruby/object:Gem::Version
124
122
  version: '0'
125
123
  - !ruby/object:Gem::Dependency
126
124
  name: pry
127
125
  requirement: !ruby/object:Gem::Requirement
128
126
  requirements:
129
- - - ">="
127
+ - - "~>"
130
128
  - !ruby/object:Gem::Version
131
129
  version: '0'
132
130
  type: :development
133
131
  prerelease: false
134
132
  version_requirements: !ruby/object:Gem::Requirement
135
133
  requirements:
136
- - - ">="
134
+ - - "~>"
137
135
  - !ruby/object:Gem::Version
138
136
  version: '0'
139
- description: A Test Kitchen Driver for Cloudstack
137
+ description: A Test Kitchen Driver for Apache CloudStack
140
138
  email:
141
139
  - fifthecho@gmail.com
142
140
  executables: []
@@ -155,7 +153,7 @@ files:
155
153
  - kitchen-cloudstack.gemspec
156
154
  - lib/kitchen/driver/cloudstack.rb
157
155
  - lib/kitchen/driver/cloudstack_version.rb
158
- homepage: https://github.com/fifthecho/kitchen-cloudstack
156
+ homepage: https://github.com/test-kitchen/kitchen-cloudstack
159
157
  licenses:
160
158
  - Apache 2.0
161
159
  metadata: {}
@@ -175,8 +173,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
173
  version: '0'
176
174
  requirements: []
177
175
  rubyforge_project:
178
- rubygems_version: 2.0.14
176
+ rubygems_version: 2.2.2
179
177
  signing_key:
180
178
  specification_version: 4
181
- summary: A Test Kitchen Driver for Cloudstack
179
+ summary: Provides an interface for Test Kitchen to be able to run jobs against an
180
+ Apache CloudStack cloud.
182
181
  test_files: []
182
+ has_rdoc: