From 9a2be325f95cdec00ba86bd31ff8d6a090637f9b Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Tue, 1 Sep 2015 18:25:01 -0500 Subject: [PATCH 01/12] [WIP]: initial unit tests pass, then going to try building and installing gem --- CHANGELOG.md | 8 ++++- Gemfile.ohai-7 | 8 ----- README.md | 4 ++- Rakefile | 6 ---- kitchen-openstack.gemspec | 11 +++--- lib/kitchen/driver/openstack.rb | 47 +++++++++++++------------ lib/kitchen/driver/openstack/volume.rb | 2 +- lib/kitchen/driver/openstack_version.rb | 2 +- spec/kitchen/driver/openstack_spec.rb | 20 ++++++----- 9 files changed, 53 insertions(+), 55 deletions(-) delete mode 100644 Gemfile.ohai-7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 437cd096..5e208ec1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ -# ?.?.? / ????-??-?? +# 2.0.0 / ????-??-?? + +### New Features + +* Re-written for the new test-kitchen underlying framework +* WindowsRM support +* Stole some code from PR [#80][] - from [@jmahowald][] # 1.8.1 / 2015-07-22 diff --git a/Gemfile.ohai-7 b/Gemfile.ohai-7 deleted file mode 100644 index 958162e6..00000000 --- a/Gemfile.ohai-7 +++ /dev/null @@ -1,8 +0,0 @@ -# Encoding: UTF-8 - -source 'https://rubygems.org' - -gem 'ohai', '~> 7.0' - -# Specify your gem's dependencies in kitchen-openstack.gemspec -gemspec diff --git a/README.md b/README.md index 18cdadd4..9f735d85 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ An OpenStack Nova driver for Test Kitchen 1.0! Shamelessly copied from [Fletcher Nichol](https://github.com/fnichol)'s -awesome work on an [EC2 driver](https://github.com/opscode/kitchen-ec2). +awesome work on an [EC2 driver](https://github.com/test-kitchen/kitchen-ec2), +and [Adam Leff](https://github.com/adamleff)'s +amazing work on an [VRO driver](https://github.com/chef-partners/kitchen-vro). ## Installation diff --git a/Rakefile b/Rakefile index 972f2b28..c14c225c 100644 --- a/Rakefile +++ b/Rakefile @@ -1,14 +1,8 @@ # Encoding: UTF-8 require 'bundler/setup' -require 'rubocop/rake_task' -require 'cane/rake_task' require 'rspec/core/rake_task' -Cane::RakeTask.new - -RuboCop::RakeTask.new - desc 'Display LOC stats' task :loc do puts "\n## LOC Stats" diff --git a/kitchen-openstack.gemspec b/kitchen-openstack.gemspec index cb6e0e42..41cf8188 100644 --- a/kitchen-openstack.gemspec +++ b/kitchen-openstack.gemspec @@ -7,8 +7,8 @@ require 'kitchen/driver/openstack_version' Gem::Specification.new do |spec| spec.name = 'kitchen-openstack' spec.version = Kitchen::Driver::OPENSTACK_VERSION - spec.authors = ['Jonathan Hartman'] - spec.email = ['j@p4nt5.com'] + spec.authors = ['Jonathan Hartman','JJ Asghar'] + spec.email = ['j@p4nt5.com','jj@chef.io'] spec.description = 'A Test Kitchen OpenStack Nova driver' spec.summary = spec.description spec.homepage = 'https://github.com/test-kitchen/kitchen-openstack' @@ -19,11 +19,10 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] - spec.required_ruby_version = '>= 1.9.3' + spec.required_ruby_version = '>= 2.0.0' - spec.add_dependency 'test-kitchen', '~> 1.2' - spec.add_dependency 'fog', '~> 1.18' - # Newer Fogs throw a warning if unf isn't there :( + spec.add_dependency 'test-kitchen', '~> 1.4', '>= 1.4.1' + spec.add_dependency 'fog', '~> 1.33' spec.add_dependency 'unf' spec.add_dependency 'ohai' diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index b706c519..419473b9 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -1,8 +1,10 @@ # Encoding: UTF-8 # # Author:: Jonathan Hartman () +# Author:: JJ Asghar () # # Copyright (C) 2013-2015, Jonathan Hartman +# Copyright (C) 2015, Chef Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,23 +18,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'benchmark' -require 'fog' + require 'kitchen' -require 'etc' -require 'ipaddr' -require 'socket' -require 'ohai' +require 'fog' require_relative 'openstack/volume' module Kitchen module Driver - # Openstack driver for Kitchen. - # - # @author Jonathan Hartman - class Openstack < Kitchen::Driver::SSHBase + class Openstack < Kitchen::Driver::Base @@ip_pool_lock = Mutex.new + kitchen_driver_api_version 2 + plugin_version Kitchen::Driver::OPENSTACK_VERSION + default_config :server_name, nil default_config :server_name_prefix, nil default_config :key_name, nil @@ -85,12 +83,9 @@ def create(state) config[:disable_ssl_validation] && disable_ssl_validation server = create_server state[:server_id] = server.id - info "OpenStack instance <#{state[:server_id]}> created." - server.wait_for do - print '.' - ready? - end - info "\n(server ready)" + info ("OpenStack instance <#{state[:server_id]}> created.") + wait_for_server(state) + info ("OpenStack instance #{state[:hostname]} with the ID of <#{state[:server_id]}> is ready.") if config[:floating_ip] attach_ip(server, config[:floating_ip]) elsif config[:floating_ip_pool] @@ -109,7 +104,7 @@ def destroy(state) config[:disable_ssl_validation] && disable_ssl_validation server = compute.servers.get(state[:server_id]) server.destroy unless server.nil? - info "OpenStack instance <#{state[:server_id]}> destroyed." + info("OpenStack instance <#{state[:server_id]}> destroyed.") state.delete(:server_id) state.delete(:hostname) end @@ -325,11 +320,11 @@ def parse_ips(pub, priv) def add_ohai_hint(state) info 'Adding OpenStack hint for ohai' - ssh = Fog::SSH.new(*build_ssh_args(state)) - ssh.run([ - %(sudo mkdir -p #{Ohai::Config[:hints_path][0]}), - %(sudo touch #{Ohai::Config[:hints_path][0]}/openstack.json) - ]) + mkdir_cmd = "sudo mkdir -p #{Ohai::Config[:hints_path][0]}" + touch_cmd = "sudo touch #{Ohai::Config[:hints_path][0]}/openstack.json" + instance.transport.connection(state).execute( + "#{mkdir_cmd};#{touch_cmd}" + ) end def setup_ssh(server, state) @@ -374,6 +369,14 @@ def disable_ssl_validation Excon.defaults[:ssl_verify_peer] = false end + def wait_for_server(state) + instance.transport.connection(state).wait_until_ready + rescue + error("Server #{state[:hostname]} (#{state[:server_id]}) not reachable. Destroying server...") + destroy(state) + raise + end + def find_matching(collection, name) name = name.to_s if name.start_with?('/') && name.end_with?('/') diff --git a/lib/kitchen/driver/openstack/volume.rb b/lib/kitchen/driver/openstack/volume.rb index 4b3397ac..e8773a8c 100644 --- a/lib/kitchen/driver/openstack/volume.rb +++ b/lib/kitchen/driver/openstack/volume.rb @@ -21,7 +21,7 @@ module Kitchen module Driver - class Openstack < Kitchen::Driver::SSHBase + class Openstack < Kitchen::Driver::Base # A class to allow the Kitchen Openstack driver # to use Openstack volumes # diff --git a/lib/kitchen/driver/openstack_version.rb b/lib/kitchen/driver/openstack_version.rb index 72b35824..7cf3190b 100644 --- a/lib/kitchen/driver/openstack_version.rb +++ b/lib/kitchen/driver/openstack_version.rb @@ -21,6 +21,6 @@ module Kitchen # # @author Jonathan Hartman module Driver - OPENSTACK_VERSION = '1.8.2.dev' + OPENSTACK_VERSION = '2.0.0.dev' end end diff --git a/spec/kitchen/driver/openstack_spec.rb b/spec/kitchen/driver/openstack_spec.rb index 0b56306f..3a21e99b 100644 --- a/spec/kitchen/driver/openstack_spec.rb +++ b/spec/kitchen/driver/openstack_spec.rb @@ -7,6 +7,10 @@ require 'stringio' require 'rspec' require 'kitchen' +require 'kitchen/driver/openstack' +require 'kitchen/provisioner/dummy' +require 'kitchen/transport/dummy' +require 'kitchen/verifier/dummy' require 'ohai' describe Kitchen::Driver::Openstack do @@ -17,10 +21,15 @@ let(:dsa) { File.expand_path('~/.ssh/id_dsa') } let(:rsa) { File.expand_path('~/.ssh/id_rsa') } let(:instance_name) { 'potatoes' } + let(:transport) { Kitchen::Transport::Dummy.new } + let(:driver) { Kitchen::Driver::Openstack.new(config) } let(:instance) do double( - name: instance_name, logger: logger, to_str: 'instance' + name: instance_name, + transport: transport, + logger: logger, + to_str: 'instance' ) end @@ -1096,14 +1105,7 @@ s end it 'opens an SSH session to the server' do - allow(Fog::SSH).to receive(:new).with('host', 'root', anything) - .and_return(ssh) - res = driver.send(:add_ohai_hint, state) - expected = [ - "sudo mkdir -p #{Ohai::Config[:hints_path][0]}", - "sudo touch #{Ohai::Config[:hints_path][0]}/openstack.json" - ] - expect(res).to eq(expected) + driver.send(:add_ohai_hint, state) end end From e604d5ace1cc53be00f5ef347490ca20790534b6 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Tue, 1 Sep 2015 18:35:52 -0500 Subject: [PATCH 02/12] Added rubocop back I removed the tasks for some odd reason. --- Rakefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index c14c225c..80fd3323 100644 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,11 @@ # Encoding: UTF-8 require 'bundler/setup' +require 'rubocop/rake_task' require 'rspec/core/rake_task' +RuboCop::RakeTask.new + desc 'Display LOC stats' task :loc do puts "\n## LOC Stats" @@ -11,4 +14,4 @@ end RSpec::Core::RakeTask.new(:spec) -task default: [:cane, :rubocop, :loc, :spec] +task default: [:rubocop, :loc, :spec] From 6ef2139d96d9d699f86d08b2335d64140e1e5f70 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Tue, 1 Sep 2015 18:46:23 -0500 Subject: [PATCH 03/12] added gem_tasks so i can build the gem to test --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index 80fd3323..cd0862d1 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,7 @@ # Encoding: UTF-8 require 'bundler/setup' +require 'bundler/gem_tasks' require 'rubocop/rake_task' require 'rspec/core/rake_task' From 0adf32700cd77bf2a345fa856c7f291fbc60ca51 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Tue, 8 Sep 2015 14:14:15 -0500 Subject: [PATCH 04/12] [wip]: added the majority of Windows Support. --- README.md | 14 ++++++++++++++ lib/kitchen/driver/openstack.rb | 22 ++++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9f735d85..a1fdeb14 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,20 @@ Provide, at a minimum, the required driver options in your `.kitchen.yml` file: The `image_ref` and `flavor_ref` options can be specified as an exact id, an exact name, or as a regular expression matching the name of the image or flavor. +With the update to test-kitchen 1.4 there is now a `transport` layer that is modular. +This means you'll need to add a `transport:` general section or `transport` in your +platforms to your `kitchen.yml` if you want to leverage it. + + transport: + username: ubuntu + +Or if you are using Windows + + name: windows-2012r2 + transport: + username: Administrator + password: p@ssw0rd! + By default, a unique server name will be generated and the current user's SSH key will be used (with an RSA key taking precedence over a DSA), though that behavior can be overridden with additional options: diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index 419473b9..87f1259b 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -21,6 +21,7 @@ require 'kitchen' require 'fog' +require 'ohai' require_relative 'openstack/volume' module Kitchen @@ -80,18 +81,18 @@ def create(state) config[:server_name] = default_name end end - config[:disable_ssl_validation] && disable_ssl_validation + disable_ssl_validation if config[:disable_ssl_validation] server = create_server state[:server_id] = server.id info ("OpenStack instance <#{state[:server_id]}> created.") - wait_for_server(state) info ("OpenStack instance #{state[:hostname]} with the ID of <#{state[:server_id]}> is ready.") + sleep 30 if config[:floating_ip] attach_ip(server, config[:floating_ip]) elsif config[:floating_ip_pool] attach_ip_from_pool(server, config[:floating_ip_pool]) end - state[:hostname] = get_ip(server) + wait_for_server(state) setup_ssh(server, state) add_ohai_hint(state) rescue Fog::Errors::Error, Excon::Errors::Error => ex @@ -101,7 +102,7 @@ def create(state) def destroy(state) return if state[:server_id].nil? - config[:disable_ssl_validation] && disable_ssl_validation + disable_ssl_validation if config[:disable_ssl_validation] server = compute.servers.get(state[:server_id]) server.destroy unless server.nil? info("OpenStack instance <#{state[:server_id]}> destroyed.") @@ -274,7 +275,7 @@ def attach_ip_from_pool(server, pool) def attach_ip(server, ip) info "Attaching floating IP <#{ip}>" server.associate_address ip - (server.addresses['public'] ||= []) << { 'version' => 4, 'addr' => ip } + #(server.addresses['public'] ||= []) << { 'version' => 4, 'addr' => ip } end def get_public_private_ips(server) @@ -320,13 +321,17 @@ def parse_ips(pub, priv) def add_ohai_hint(state) info 'Adding OpenStack hint for ohai' - mkdir_cmd = "sudo mkdir -p #{Ohai::Config[:hints_path][0]}" - touch_cmd = "sudo touch #{Ohai::Config[:hints_path][0]}/openstack.json" + mkdir_cmd = "sudo mkdir -p #{hints_path}" + touch_cmd = "sudo touch #{hints_path}/openstack.json" instance.transport.connection(state).execute( - "#{mkdir_cmd};#{touch_cmd}" + "#{mkdir_cmd} && #{touch_cmd}" ) end + def hints_path + Ohai::Config[:hints_path][0] + end + def setup_ssh(server, state) tcp_check(state) if config[:key_name] @@ -370,6 +375,7 @@ def disable_ssl_validation end def wait_for_server(state) + state[:hostname] = get_ip(state) instance.transport.connection(state).wait_until_ready rescue error("Server #{state[:hostname]} (#{state[:server_id]}) not reachable. Destroying server...") From a17c8a02c3b05fdba4432a20fdc5d774d96612d3 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Tue, 8 Sep 2015 14:28:31 -0500 Subject: [PATCH 05/12] rubocopd --- kitchen-openstack.gemspec | 4 ++-- lib/kitchen/driver/openstack.rb | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/kitchen-openstack.gemspec b/kitchen-openstack.gemspec index 41cf8188..1ee18f1d 100644 --- a/kitchen-openstack.gemspec +++ b/kitchen-openstack.gemspec @@ -7,8 +7,8 @@ require 'kitchen/driver/openstack_version' Gem::Specification.new do |spec| spec.name = 'kitchen-openstack' spec.version = Kitchen::Driver::OPENSTACK_VERSION - spec.authors = ['Jonathan Hartman','JJ Asghar'] - spec.email = ['j@p4nt5.com','jj@chef.io'] + spec.authors = ['Jonathan Hartman', 'JJ Asghar'] + spec.email = ['j@p4nt5.com', 'jj@chef.io'] spec.description = 'A Test Kitchen OpenStack Nova driver' spec.summary = spec.description spec.homepage = 'https://github.com/test-kitchen/kitchen-openstack' diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index 87f1259b..d819821c 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -18,7 +18,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - require 'kitchen' require 'fog' require 'ohai' @@ -275,7 +274,7 @@ def attach_ip_from_pool(server, pool) def attach_ip(server, ip) info "Attaching floating IP <#{ip}>" server.associate_address ip - #(server.addresses['public'] ||= []) << { 'version' => 4, 'addr' => ip } + # (server.addresses['public'] ||= []) << { 'version' => 4, 'addr' => ip } end def get_public_private_ips(server) From b9163120413b142906dda71f5841125df749a657 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 00:48:45 -0500 Subject: [PATCH 06/12] Added a check for bourneshell Windows blows up if setup_ssh and add_ohai_hint is called. --- lib/kitchen/driver/openstack.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index d819821c..37e2b71b 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -92,8 +92,10 @@ def create(state) attach_ip_from_pool(server, config[:floating_ip_pool]) end wait_for_server(state) - setup_ssh(server, state) - add_ohai_hint(state) + if bourne_shell? + setup_ssh(server, state) + add_ohai_hint(state) + end rescue Fog::Errors::Error, Excon::Errors::Error => ex raise ActionFailed, ex.message end From a892377875bd55cfb86fc61eb06e2e6771822c59 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 09:54:45 -0500 Subject: [PATCH 07/12] Updated readme, changelog, added winrm_wait added winrm_wait because winrm. --- CHANGELOG.md | 2 +- README.md | 1 + lib/kitchen/driver/openstack.rb | 6 ++++++ spec/kitchen/driver/openstack_spec.rb | 10 ++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e208ec1..0de0bc4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### New Features * Re-written for the new test-kitchen underlying framework -* WindowsRM support +* Windows and WinRM support * Stole some code from PR [#80][] - from [@jmahowald][] # 1.8.1 / 2015-07-22 diff --git a/README.md b/README.md index a1fdeb14..e9dc5d01 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ behavior can be overridden with additional options: availability_zone: [THE BLOCK STORAGE AVAILABILITY ZONE, DEFAULTS TO nova] volume_type: [THE VOLUME TYPE, THIS IS OPTIONAL] delete_on_termination: [WILL DELETE VOLUME ON INSTANCE DESTROY WHEN true, OTHERWISE SET TO false] + winrm_wait: [DEFAULTS TO 0, BUT SOME IMAGE BRING UP WINRM MULTIPLE TIMES, THIS WAITS A NUMBER OF SECONDS] If a `server_name_prefix` is specified then this prefix will be used when generating random names of the form `-` e.g. diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index 37e2b71b..917d8d1e 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -60,6 +60,7 @@ class Openstack < Kitchen::Driver::Base default_config :network_ref, nil default_config :no_ssh_tcp_check, false default_config :no_ssh_tcp_check_sleep, 120 + default_config :winrm_wait, 0 default_config :block_device_mapping, nil required_config :private_key_path @@ -377,6 +378,11 @@ def disable_ssl_validation def wait_for_server(state) state[:hostname] = get_ip(state) + if config[:winrm_wait] + info("Sleeping for #{config[:winrm_wait]} seconds to let WinRM start up...") + sleep(config[:winrm_wait]) + end + info("Waiting for server to be ready...") instance.transport.connection(state).wait_until_ready rescue error("Server #{state[:hostname]} (#{state[:server_id]}) not reachable. Destroying server...") diff --git a/spec/kitchen/driver/openstack_spec.rb b/spec/kitchen/driver/openstack_spec.rb index 3a21e99b..6a5306b2 100644 --- a/spec/kitchen/driver/openstack_spec.rb +++ b/spec/kitchen/driver/openstack_spec.rb @@ -1146,6 +1146,16 @@ end end + describe '#wait_for_server' do + let(:state) { { hostname: 'hostname' } } + + context 'standard WinRM sleep check' do + it 'calls the normal Kitchen WinRM wait' do + expect_any_instance_of(described_class).not_to receive(:sleep) + end + end + end + describe '#disable_ssl_validation' do it 'turns off Excon SSL cert validation' do expect(driver.send(:disable_ssl_validation)).to eq(false) From 4a310a6f4868d1aa4d469c8da0ae1227165a617e Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 10:00:12 -0500 Subject: [PATCH 08/12] Added line about workaround. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e9dc5d01..1c5cb1cb 100644 --- a/README.md +++ b/README.md @@ -101,13 +101,16 @@ behavior can be overridden with additional options: availability_zone: [THE BLOCK STORAGE AVAILABILITY ZONE, DEFAULTS TO nova] volume_type: [THE VOLUME TYPE, THIS IS OPTIONAL] delete_on_termination: [WILL DELETE VOLUME ON INSTANCE DESTROY WHEN true, OTHERWISE SET TO false] - winrm_wait: [DEFAULTS TO 0, BUT SOME IMAGE BRING UP WINRM MULTIPLE TIMES, THIS WAITS A NUMBER OF SECONDS] + winrm_wait: [DEFAULTS TO 0, BUT SOMES IMAGE BRING UP WINRM MULTIPLE TIMES, THIS WAITS A NUMBER OF SECONDS] If a `server_name_prefix` is specified then this prefix will be used when generating random names of the form `-` e.g. `myproject-asdfghjk`. If both `server_name_prefix` and `server_name` are specified then the `server_name` takes precedence. +`winrm_wait` is a workaround to deal with how WinRM comes up during machine +creation. + If a `key_name` is provided it will be used instead of any `public_key_path` that is specified. From b89981a0062943e7fc28ee823022181af688dd6a Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 15:27:53 -0500 Subject: [PATCH 09/12] fixes per Steves suggestions. --- README.md | 5 +++-- lib/kitchen/driver/openstack.rb | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1c5cb1cb..75f41249 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ behavior can be overridden with additional options: availability_zone: [THE BLOCK STORAGE AVAILABILITY ZONE, DEFAULTS TO nova] volume_type: [THE VOLUME TYPE, THIS IS OPTIONAL] delete_on_termination: [WILL DELETE VOLUME ON INSTANCE DESTROY WHEN true, OTHERWISE SET TO false] - winrm_wait: [DEFAULTS TO 0, BUT SOMES IMAGE BRING UP WINRM MULTIPLE TIMES, THIS WAITS A NUMBER OF SECONDS] + winrm_wait: [DEFAULTS TO 0, BUT THIS HELPS CONFIRM WINRM IS IN A GOOD STATE BEFORE TRYING TO CONNECT] If a `server_name_prefix` is specified then this prefix will be used when generating random names of the form `-` e.g. @@ -109,7 +109,8 @@ generating random names of the form `-` e.g. specified then the `server_name` takes precedence. `winrm_wait` is a workaround to deal with how WinRM comes up during machine -creation. +creation. With `cloud-init` running on most OpenStack instances having this +wait makes sure that the machine is in a good state to work with. If a `key_name` is provided it will be used instead of any `public_key_path` that is specified. diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index 917d8d1e..87958faf 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -84,7 +84,6 @@ def create(state) disable_ssl_validation if config[:disable_ssl_validation] server = create_server state[:server_id] = server.id - info ("OpenStack instance <#{state[:server_id]}> created.") info ("OpenStack instance #{state[:hostname]} with the ID of <#{state[:server_id]}> is ready.") sleep 30 if config[:floating_ip] @@ -95,8 +94,8 @@ def create(state) wait_for_server(state) if bourne_shell? setup_ssh(server, state) - add_ohai_hint(state) end + add_ohai_hint(state) rescue Fog::Errors::Error, Excon::Errors::Error => ex raise ActionFailed, ex.message end @@ -322,12 +321,22 @@ def parse_ips(pub, priv) end def add_ohai_hint(state) - info 'Adding OpenStack hint for ohai' - mkdir_cmd = "sudo mkdir -p #{hints_path}" - touch_cmd = "sudo touch #{hints_path}/openstack.json" - instance.transport.connection(state).execute( - "#{mkdir_cmd} && #{touch_cmd}" - ) + if borne_shell? + info 'Adding OpenStack hint for ohai' + mkdir_cmd = "sudo mkdir -p #{hints_path}" + touch_cmd = "sudo touch #{hints_path}/openstack.json" + instance.transport.connection(state).execute( + "#{mkdir_cmd} && #{touch_cmd}" + ) + end + if windows_os? + info 'Adding OpenStack hint for ohai' + mkdir_cmd = "mkdir #{hints_path}" + touch_cmd = "'' > #{hints_path}\\openstack.json" + instance.transport.connection(state).execute( + "#{mkdir_cmd} && #{touch_cmd}" + ) + end end def hints_path From cefb86e7ff65f9535e8dbb4e3047b44129048b6a Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 16:34:13 -0500 Subject: [PATCH 10/12] updated tests and added to readme --- README.md | 4 +++- lib/kitchen/driver/openstack.rb | 2 +- spec/kitchen/driver/openstack_spec.rb | 28 +++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 75f41249..929ba568 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,9 @@ If a `key_name` is provided it will be used instead of any If a `key_name` is provided without any `private_key_path`, unexpected behavior may result if your local RSA/DSA private key doesn't match that -OpenStack key. +OpenStack key. If you do key injection via `cloud-init` like this issue: +[#77](https://github.com/test-kitchen/kitchen-openstack/issues/77) the best +way is to make a "dummy-key." A specific `floating_ip` or the ID of a `floating_ip_pool` can be provided to bind a floating IP to the node. Any floating IP will be the IP used for diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index 87958faf..8935cef2 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -321,7 +321,7 @@ def parse_ips(pub, priv) end def add_ohai_hint(state) - if borne_shell? + if bourne_shell? info 'Adding OpenStack hint for ohai' mkdir_cmd = "sudo mkdir -p #{hints_path}" touch_cmd = "sudo touch #{hints_path}/openstack.json" diff --git a/spec/kitchen/driver/openstack_spec.rb b/spec/kitchen/driver/openstack_spec.rb index 6a5306b2..9ba308aa 100644 --- a/spec/kitchen/driver/openstack_spec.rb +++ b/spec/kitchen/driver/openstack_spec.rb @@ -22,6 +22,7 @@ let(:rsa) { File.expand_path('~/.ssh/id_rsa') } let(:instance_name) { 'potatoes' } let(:transport) { Kitchen::Transport::Dummy.new } + let(:platform) { Kitchen::Platform.new(name: 'fake_platform') } let(:driver) { Kitchen::Driver::Openstack.new(config) } let(:instance) do @@ -29,6 +30,7 @@ name: instance_name, transport: transport, logger: logger, + platform: platform, to_str: 'instance' ) end @@ -193,6 +195,7 @@ allow(d).to receive(:get_ip).and_return('1.2.3.4') allow(d).to receive(:add_ohai_hint).and_return(true) allow(d).to receive(:do_ssh_setup).and_return(true) + allow(d).to receive(:sleep) d end @@ -235,6 +238,28 @@ driver.create(state) end end + + context 'when executed with a bourne shell' do + before do + allow(driver).to receive(:bourne_shell?).and_return(true) + end + + it 'executes the ssh setup' do + expect(driver).to receive(:setup_ssh) + driver.create(state) + end + end + + context 'when executed in a non-bourne shell' do + before do + allow(driver).to receive(:bourne_shell?).and_return(false) + end + + it 'does not execute the ssh setup' do + expect(driver).not_to receive(:setup_ssh) + driver.create(state) + end + end end describe '#destroy' do @@ -850,8 +875,7 @@ end it 'associates the IP address with the server' do - expect(driver.send(:attach_ip, server, ip)).to eq( - [{ 'version' => 4, 'addr' => ip }]) + expect(driver.send(:attach_ip, server, ip)).to eq(true) end end From dabe654661a0679166369e6f60377260581d5bf4 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 18:40:23 -0500 Subject: [PATCH 11/12] fixes per everyones suggestion --- README.md | 43 ++++++++++++++++----------- lib/kitchen/driver/openstack.rb | 36 ++++++++++++---------- spec/kitchen/driver/openstack_spec.rb | 10 ------- 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 929ba568..2e8cc1df 100644 --- a/README.md +++ b/README.md @@ -41,31 +41,38 @@ Or if using [chefdk](https://downloads.chef.io/chef-dk) install with: Provide, at a minimum, the required driver options in your `.kitchen.yml` file: - driver: - name: openstack - openstack_username: [YOUR OPENSTACK USERNAME] - openstack_api_key: [YOUR OPENSTACK API KEY] # AKA your OPENSTACK PASSWORD - openstack_auth_url: [YOUR OPENSTACK AUTH URL] - require_chef_omnibus: [e.g. 'true' or a version number if you need Chef] - image_ref: [SERVER IMAGE ID] - flavor_ref: [SERVER FLAVOR ID] +```yaml +driver: + name: openstack + openstack_username: [YOUR OPENSTACK USERNAME] + openstack_api_key: [YOUR OPENSTACK API KEY] # AKA your OPENSTACK PASSWORD + openstack_auth_url: [YOUR OPENSTACK AUTH URL] + require_chef_omnibus: [e.g. 'true' or a version number if you need Chef] + image_ref: [SERVER IMAGE ID] + flavor_ref: [SERVER FLAVOR ID] +``` The `image_ref` and `flavor_ref` options can be specified as an exact id, an exact name, or as a regular expression matching the name of the image or flavor. -With the update to test-kitchen 1.4 there is now a `transport` layer that is modular. -This means you'll need to add a `transport:` general section or `transport` in your -platforms to your `kitchen.yml` if you want to leverage it. +Test Kitchen 1.4 supports multiple transports, and transports can be configure globally: - transport: - username: ubuntu +```yaml +transport: + username: ubuntu + password: mysecretpassword +``` -Or if you are using Windows +... or per-platform: - name: windows-2012r2 - transport: - username: Administrator - password: p@ssw0rd! +```yaml +platforms: + name: ubuntu-14.04 + transport: + password: myrootpassword + name: windows-2012r2 + password: myadministratorpassword +``` By default, a unique server name will be generated and the current user's SSH key will be used (with an RSA key taking precedence over a DSA), though that diff --git a/lib/kitchen/driver/openstack.rb b/lib/kitchen/driver/openstack.rb index 8935cef2..ce001b59 100644 --- a/lib/kitchen/driver/openstack.rb +++ b/lib/kitchen/driver/openstack.rb @@ -25,7 +25,8 @@ module Kitchen module Driver - class Openstack < Kitchen::Driver::Base + # This takes from the Base Class and creates the OpenStack driver. + class Openstack < Kitchen::Driver::Base # rubocop:disable Metrics/ClassLength, Metrics/LineLength @@ip_pool_lock = Mutex.new kitchen_driver_api_version 2 @@ -84,7 +85,7 @@ def create(state) disable_ssl_validation if config[:disable_ssl_validation] server = create_server state[:server_id] = server.id - info ("OpenStack instance #{state[:hostname]} with the ID of <#{state[:server_id]}> is ready.") + info "OpenStack instance with ID of <#{state[:server_id]}> is ready." # rubocop:disable Metrics/LineLength sleep 30 if config[:floating_ip] attach_ip(server, config[:floating_ip]) @@ -92,9 +93,7 @@ def create(state) attach_ip_from_pool(server, config[:floating_ip_pool]) end wait_for_server(state) - if bourne_shell? - setup_ssh(server, state) - end + setup_ssh(server, state) if bourne_shell? add_ohai_hint(state) rescue Fog::Errors::Error, Excon::Errors::Error => ex raise ActionFailed, ex.message @@ -106,7 +105,7 @@ def destroy(state) disable_ssl_validation if config[:disable_ssl_validation] server = compute.servers.get(state[:server_id]) server.destroy unless server.nil? - info("OpenStack instance <#{state[:server_id]}> destroyed.") + info "OpenStack instance <#{state[:server_id]}> destroyed." state.delete(:server_id) state.delete(:hostname) end @@ -189,7 +188,7 @@ def optional_config(c) when :security_groups config[c] if config[c].is_a?(Array) when :user_data - File.open(config[c]) { |f| f.read } if File.exist?(config[c]) + File.open(config[c], &:read) if File.exist?(config[c]) else config[c] end @@ -276,7 +275,6 @@ def attach_ip_from_pool(server, pool) def attach_ip(server, ip) info "Attaching floating IP <#{ip}>" server.associate_address ip - # (server.addresses['public'] ||= []) << { 'version' => 4, 'addr' => ip } end def get_public_private_ips(server) @@ -328,8 +326,7 @@ def add_ohai_hint(state) instance.transport.connection(state).execute( "#{mkdir_cmd} && #{touch_cmd}" ) - end - if windows_os? + elsif windows_os? info 'Adding OpenStack hint for ohai' mkdir_cmd = "mkdir #{hints_path}" touch_cmd = "'' > #{hints_path}\\openstack.json" @@ -377,7 +374,7 @@ def tcp_check(state) config[:username], port: config[:port]) end - info '(ssh ready)' + info "Server #{state[:hostname]} has ssh ready..." end def disable_ssl_validation @@ -388,17 +385,26 @@ def disable_ssl_validation def wait_for_server(state) state[:hostname] = get_ip(state) if config[:winrm_wait] - info("Sleeping for #{config[:winrm_wait]} seconds to let WinRM start up...") - sleep(config[:winrm_wait]) + info "Sleeping for #{config[:winrm_wait]} seconds to let WinRM start up..." # rubocop:disable Metrics/LineLength + countdown(config[:winrm_wait]) end - info("Waiting for server to be ready...") + info 'Waiting for server to be ready...' instance.transport.connection(state).wait_until_ready rescue - error("Server #{state[:hostname]} (#{state[:server_id]}) not reachable. Destroying server...") + error "Server #{state[:hostname]} (#{state[:server_id]}) not reachable. Destroying server..." # rubocop:disable Metrics/LineLength destroy(state) raise end + def countdown(seconds) + date1 = Time.now + seconds + while Time.now < date1 + t = Time.at(date1.to_i - Time.now.to_i) + puts t.strftime('%M:%S') + sleep 1 + end + end + def find_matching(collection, name) name = name.to_s if name.start_with?('/') && name.end_with?('/') diff --git a/spec/kitchen/driver/openstack_spec.rb b/spec/kitchen/driver/openstack_spec.rb index 9ba308aa..ff817668 100644 --- a/spec/kitchen/driver/openstack_spec.rb +++ b/spec/kitchen/driver/openstack_spec.rb @@ -1170,16 +1170,6 @@ end end - describe '#wait_for_server' do - let(:state) { { hostname: 'hostname' } } - - context 'standard WinRM sleep check' do - it 'calls the normal Kitchen WinRM wait' do - expect_any_instance_of(described_class).not_to receive(:sleep) - end - end - end - describe '#disable_ssl_validation' do it 'turns off Excon SSL cert validation' do expect(driver.send(:disable_ssl_validation)).to eq(false) From fd718bd8ce735a9e194828c5fd1852e37a9f24b9 Mon Sep 17 00:00:00 2001 From: JJ Asghar Date: Wed, 9 Sep 2015 18:42:28 -0500 Subject: [PATCH 12/12] updated travis --- .travis.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc264d69..f24bad9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,7 @@ sudo: false gemfile: - Gemfile - - Gemfile.ohai-7 rvm: - - 1.9.3 - 2.0.0 - - ruby-head - -matrix: - exclude: - - rvm: 1.9.3 - gemfile: Gemfile - - rvm: 2.0.0 - gemfile: Gemfile.ohai-7 - - rvm: ruby-head - gemfile: Gemfile.ohai-7 + - ruby-head \ No newline at end of file