Skip to content

Commit

Permalink
wip: cleanup and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
thmttch committed Apr 20, 2014
1 parent 1b82b9c commit 30eb44e
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 79 deletions.
9 changes: 6 additions & 3 deletions .kitchen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ provisioner:
name: chef_solo

platforms:
#- name: ubuntu-12.04
#- name: ubuntu-12.10
#- name: ubuntu-13.04
- name: ubuntu-12.04
- name: ubuntu-12.10
- name: ubuntu-13.04
- name: ubuntu-13.10

suites:
- name: default
run_list:
- recipe[chef-continuum-anaconda::default]
attributes:
anaconda:
version: '1.8.0'
flavor: 'x86'
5 changes: 3 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gem 'chefspec'

gem 'test-kitchen'
gem 'kitchen-vagrant'
#gem 'serverspec'

gem 'psych', '2.0.5'
gem 'foodcritic'

#gem 'psych', '2.0.5'
63 changes: 59 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,72 @@
# chef-continuum-anaconda cookbook

Chef cookbook for installing [Continuum Analytic](http://continuum.io/)'s
[Anaconda](https://store.continuum.io/cshop/anaconda/): "completely free Python
distribution for large-scale data processing, predictive analytics, and
scientific computing".

This also serves as a example of the most up-to-date best practices for
writing, maintaining, and testing Chef cookbooks:

- Berkshelf 3 for dependency resolution
- Vagrant for development
- Chefspec for rapid testing
- Test Kitchen for comprehensive testing across multiple platforms
- Foodcritic for style checking

# Requirements

# Usage
# Usage, recipes, and attributes

# Attributes
This cookbook only has one recipe: `chef-continuum-anaconda::default`. Include
it in your runlist, and it will install the package as well as any necessary
dependencies.

# Recipes
The following are user-configurable attributes. Check <attributes/default.rb> for default values.

# Author
- anaconda
- version: the version to install
- flavor: either 'x86' (32-bit) or 'x86_64' (64-bit)
- install_root: the parent directory of all anaconda installs. note that installs go into `#{install_root}/#{version}`
- add_to_shell_path: TODO
- owner: the user who owns the install
- group: the group who owns the install

# Tests

Run the full test suite:

```bash
# this will take a long time
$> script/cibuild
...

# check the final result; bash return codes: 0 is good, anything else is not
$> echo $?
```

Run just the [chefspec](https://github.com/sethvargo/chefspec)s:

```bash
$> rspec
```

Run just the [test kitchen](https://github.com/test-kitchen/test-kitchen) full integration tests:

```bash
$> rspec
```

Check the style with [Foodcritic](http://acrmp.github.io/foodcritic/):

```bash
$> foodcritic
```

# TODO

- autodetect 64-bit versus 32

# Author

Author:: Matt Chu ([email protected])
20 changes: 10 additions & 10 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
config.vm.hostname = "chef-continuum-anaconda-berkshelf"
config.vm.box = "precise32"
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
config.vm.network :private_network, ip: "33.33.33.123"
Vagrant.configure('2') do |config|
config.vm.hostname = 'chef-continuum-anaconda-berkshelf'
config.vm.box = 'precise32'
config.vm.box_url = 'http://files.vagrantup.com/precise32.box'
config.vm.network :private_network, ip: '33.33.33.123'

# ssh
config.ssh.forward_x11 = true
Expand All @@ -17,17 +17,17 @@ Vagrant.configure("2") do |config|

# provisioning

# anaconda's big, so put it in the cache for development
# dev optimization: anaconda's big, so put it in the cache for development if
# it's already been downloaded
[
'Anaconda-1.8.0-Linux-x86.sh',
'Anaconda-1.8.0-Linux-x86_64.sh',
'Anaconda-1.9.2-Linux-x86.sh',
'Anaconda-1.9.2-Linux-x86_64.sh',
].each do |f|
if File.exists?(f)
#config.trigger.before [ :provision ], :execute => "bash -c 'cp /vagrant/Anaconda-1.8.0-Linux-x86.sh /var/chef/cache'", :stdout => true
config.vm.provision :shell do |shell|
shell.inline = "if [[ ! -f $1 ]]; then cp $1 $2; fi"
shell.inline = 'if [[ ! -f $1 ]]; then cp $1 $2; fi'
shell.args = [ "/vagrant/#{f}", '/var/chef/cache' ]
end
end
Expand All @@ -36,13 +36,13 @@ Vagrant.configure("2") do |config|
config.vm.provision :chef_solo do |chef|
chef.json = {
:anaconda => {
:version => '1.8.0',
:version => '1.9.2',
:flavor => 'x86',
}
}

chef.run_list = [
"recipe[chef-continuum-anaconda::default]"
'recipe[chef-continuum-anaconda::default]',
]
end
end
9 changes: 7 additions & 2 deletions attributes/default.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
default.anaconda.version = '1.8.0'
default.anaconda.version = '1.9.2'
default.anaconda.flavor = 'x86'
default.anaconda.installer = {
'1.8.0' => {
Expand All @@ -11,5 +11,10 @@
},
}

# specific versions are installed _under_ this directory
default.anaconda.install_root = '/opt/anaconda'
default.anaconda.add_to_shell_path = true
# setting this to true is not recommended; if the installation dir changes the path won't change
default.anaconda.add_to_shell_path = false

default.anaconda.owner = 'vagrant'
default.anaconda.group = 'vagrant'
2 changes: 2 additions & 0 deletions metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
version '0.1.0'

supports 'ubuntu', '= 12.04'
supports 'ubuntu', '= 13.04'
supports 'ubuntu', '= 13.10'

depends 'apt'
depends 'python'
34 changes: 20 additions & 14 deletions recipes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,26 @@
include_recipe 'apt::default'
include_recipe 'python::default'

anaconda_install_dir = node.anaconda.install_root
add_to_shell_path = node.anaconda.add_to_shell_path
version = node.anaconda.version
flavor = node.anaconda.flavor

anaconda_install_dir = "#{node.anaconda.install_root}/#{version}"
add_to_shell_path = node.anaconda.add_to_shell_path
installer = "Anaconda-#{version}-Linux-#{flavor}.sh"
installer_path = "#{Chef::Config[:file_cach_path]}/#{installer}"
installer_config = 'installer_config'
installer_config_path = "#{Chef::Config[:file_cache_path]}/#{installer_config}"

Chef::Log.debug "installer = #{installer}"
debconf_template = "anaconda-debconf"
debconf_template_path = "#{Chef::Config[:file_cache_path]}/#{debconf_template}"

remote_file "#{Chef::Config[:file_cache_path]}/#{installer}" do
remote_file installer_path do
source "http://09c8d0b2229f813c1b93-c95ac804525aac4b6dba79b00b39d1d3.r79.cf1.rackcdn.com/#{installer}"
checksum node.anaconda.installer[version][flavor]
notifies :run, 'bash[run anaconda installer]', :delayed
end

#template "#{Chef::Config[:file_cache_path]}/#{installer}.debconf" do
template debconf_template_path do
source "#{debconf_template}.erb"
#owner
#group
#mode
template installer_config_path do
source "#{installer_config}.erb"
variables({
:version => version,
:flavor => flavor,
Expand All @@ -39,9 +38,16 @@
})
end

directory node.anaconda.install_root do
owner node.anaconda.owner
group node.anaconda.group
recursive true
end

bash 'run anaconda installer' do
code "cat #{debconf_template_path} | bash #{Chef::Config[:file_cache_path]}/#{installer}"
#action :run
action :nothing
code "cat #{installer_config_path} | bash #{installer_path}"
user node.anaconda.owner
group node.anaconda.group
action :run
not_if { File.directory?(anaconda_install_dir) }
end
14 changes: 14 additions & 0 deletions script/cibuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

rspec
rspec_result=$?

# this will take a long time
kitchen verify
kitchen_result=$?
kitchen destroy

if [[ ${rspec_result} -eq 0 ]] && [[ ${kitchen_result} -eq 0 ]]; then
exit 0
fi
exit 1
46 changes: 2 additions & 44 deletions spec/default_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,30 @@
require 'chefspec/berkshelf'
#require 'chefspec/server'
require 'spec_helper.rb'
#require 'aws-sdk'

=begin
describe 'continuum-anaconda:default' do
let(:log) {
Logger.new(STDOUT).tap { |l| l.level = Logger::DEBUG }
}
before do
stub_command("bash -c \"source /etc/profile && type rvm | cat | head -1 | grep -q '^rvm is a function$'\"").and_return(true)
# on the ci server it looks like this
stub_command("bash -c \"source /etc/profile.d/rvm.sh && type rvm | cat | head -1 | grep -q '^rvm is a function$'\"").and_return(true)
# stub out chef-client: https://github.com/sethvargo/chefspec/issues/364
Chef::Recipe.any_instance.stub(:include_recipe).and_call_original
Chef::Recipe.any_instance.stub(:include_recipe).with('chef-client::delete_validation').and_return(true)
end
let(:chef_run) do
ChefSpec::Runner.new
end
it 'configures xlate backups' do
chef_run.converge(described_recipe)
expect(chef_run).to create_cookbook_file('/home/distribution/backup-xlate.sh')
# TODO we use cron.d everywhere but there's no matcher for it out of the box
#expect(chef_run).to create_cron('backup-xlate')
end
end
=end

shared_examples 'general tests' do |platform, version|
context "on #{platform} #{version}" do

#let(:users) { %w[user1 user2] }
let(:chef_run) do
ChefSpec::Runner.new(platform: platform, version: version) do |node|
#node.set['foo']['users'] = users
#end.converge('foo::default')
end
end
#subject { chef_run }

it 'runs without errors. see test-kitchen tests for more comprehensive tests not possible here' do
#default.anaconda.install_root = '/opt/anaconda'
chef_run.converge(described_recipe)

#should install_package 'foo'
expect(chef_run).to include_recipe 'python::default'
#expect(chef_run).to create_directory chef_run.node.anaconda.install_root
end

it 'generates the installer template correctly' do
chef_run.converge(described_recipe)

# must be exactly 4 lines
debconf_template = "anaconda-debconf"
debconf_template_path = "#{Chef::Config[:file_cache_path]}/#{debconf_template}"
expect(chef_run).to render_file(debconf_template_path).with_content(/.*\n.*\n.*\n.*/)
installer_config_path = "#{Chef::Config[:file_cache_path]}/installer_config"
expect(chef_run).to render_file(installer_config_path).with_content(/.*\n.*\n.*\n.*/)
end

#it "creates specified users" do
##users.each { |u| expect(chef_run).to create_user u }
#end

end
end

Expand Down
File renamed without changes.

0 comments on commit 30eb44e

Please sign in to comment.