Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# ?.?.? / ????-??-??
# 2.0.0 / ????-??-??

### New Features

* Re-written for the new test-kitchen underlying framework
* Windows and WinRM support
* Stole some code from PR [#80][] - from [@jmahowald][]

# 1.8.1 / 2015-07-22

Expand Down
8 changes: 0 additions & 8 deletions Gemfile.ohai-7

This file was deleted.

50 changes: 40 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -39,18 +41,39 @@ 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.

Test Kitchen 1.4 supports multiple transports, and transports can be configure globally:

```yaml
transport:
username: ubuntu
password: mysecretpassword
```

... or per-platform:

```yaml
platforms:
name: ubuntu-14.04
transport:
password: myrootpassword
name: windows-2012r2
password: myadministratorpassword
```

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add this due to 1.4 tk.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If username and password are available in the state file (from the driver), you don't need to add them to transport, unless you want to connect with a different account.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'd like to keep this in the readme, but that's good to know. I know with my image i had to put a different administrator password in.

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:
Expand Down Expand Up @@ -85,18 +108,25 @@ 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 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 `<NAME PREFIX>-<RANDOM STRING>` 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. 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.

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
Expand Down
6 changes: 2 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Encoding: UTF-8

require 'bundler/setup'
require 'bundler/gem_tasks'
require 'rubocop/rake_task'
require 'cane/rake_task'
require 'rspec/core/rake_task'

Cane::RakeTask.new

RuboCop::RakeTask.new

desc 'Display LOC stats'
Expand All @@ -17,4 +15,4 @@ end

RSpec::Core::RakeTask.new(:spec)

task default: [:cane, :rubocop, :loc, :spec]
task default: [:rubocop, :loc, :spec]
11 changes: 5 additions & 6 deletions kitchen-openstack.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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'

Expand Down
87 changes: 59 additions & 28 deletions lib/kitchen/driver/openstack.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Encoding: UTF-8
#
# Author:: Jonathan Hartman (<j@p4nt5.com>)
# Author:: JJ Asghar (<jj@chef.io>)
#
# 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.
Expand All @@ -16,23 +18,20 @@
# 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 'fog'
require 'ohai'
require_relative 'openstack/volume'

module Kitchen
module Driver
# Openstack driver for Kitchen.
#
# @author Jonathan Hartman <j@p4nt5.com>
class Openstack < Kitchen::Driver::SSHBase
# 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
plugin_version Kitchen::Driver::OPENSTACK_VERSION

default_config :server_name, nil
default_config :server_name_prefix, nil
default_config :key_name, nil
Expand Down Expand Up @@ -62,6 +61,7 @@ class Openstack < Kitchen::Driver::SSHBase
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
Expand All @@ -82,22 +82,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]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where would this option ever get set? I don't see a configuration option in your driver or the base driver for :disable_ssl_validation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it's mentioned in the README, about being turned on ONLY if you know what you're doing. I don't think it's supposed to be used or acknowledged without specific reasons.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To @smurawski's point, while TK doesn't complain if you pass in configuration options that are not specified, it's good practice to define a default so the code self-documents the fact that options are available.

I'd recommend putting this at the top of your class:

default_config :disable_ssl_validation, false

That way it's 100% clear what the intention is, and you never have to worry about an edge case where this being nil bites you :)

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 with ID of <#{state[:server_id]}> is ready." # rubocop:disable Metrics/LineLength
sleep 30
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be configurable? Why is it needed?

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)
setup_ssh(server, state)
wait_for_server(state)
setup_ssh(server, state) if bourne_shell?
add_ohai_hint(state)
rescue Fog::Errors::Error, Excon::Errors::Error => ex
raise ActionFailed, ex.message
Expand All @@ -106,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]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.. will this ever get hit?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it's mentioned in the README, about being turned on ONLY if you know what you're doing. I don't think it's supposed to be used or acknowledged without specific reasons.

server = compute.servers.get(state[:server_id])
server.destroy unless server.nil?
info "OpenStack instance <#{state[:server_id]}> destroyed."
Expand Down Expand Up @@ -192,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
Expand Down Expand Up @@ -279,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)
Expand Down Expand Up @@ -324,12 +319,25 @@ def parse_ips(pub, priv)
end

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)
])
if bourne_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}"
)
elsif 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
Ohai::Config[:hints_path][0]
end

def setup_ssh(server, state)
Expand Down Expand Up @@ -366,14 +374,37 @@ 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
require 'excon'
Excon.defaults[:ssl_verify_peer] = false
end

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..." # rubocop:disable Metrics/LineLength
countdown(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..." # 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?('/')
Expand Down
2 changes: 1 addition & 1 deletion lib/kitchen/driver/openstack/volume.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
#
Expand Down
2 changes: 1 addition & 1 deletion lib/kitchen/driver/openstack_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ module Kitchen
#
# @author Jonathan Hartman <j@p4nt5.com>
module Driver
OPENSTACK_VERSION = '1.8.2.dev'
OPENSTACK_VERSION = '2.0.0.dev'
end
end
Loading