ridley-5.1.1/ 0000755 0000041 0000041 00000000000 13123557300 013035 5 ustar www-data www-data ridley-5.1.1/Thorfile 0000644 0000041 0000041 00000002343 13123557300 014536 0 ustar www-data www-data # encoding: utf-8
$:.push File.expand_path("../lib", __FILE__)
require 'bundler'
require 'bundler/setup'
require 'buff/ruby_engine'
require 'ridley'
class Default < Thor
extend Buff::RubyEngine
unless jruby?
require 'thor/rake_compat'
include Thor::RakeCompat
Bundler::GemHelper.install_tasks
desc "build", "Build ridley-#{Ridley::VERSION}.gem into the pkg directory"
def build
Rake::Task["build"].invoke
end
desc "install", "Build and install ridley-#{Ridley::VERSION}.gem into system gems"
def install
Rake::Task["install"].invoke
end
desc "release", "Create tag v#{Ridley::VERSION} and build and push ridley-#{Ridley::VERSION}.gem to Rubygems"
def release
Rake::Task["release"].invoke
end
end
class Spec < Thor
namespace :spec
default_task :all
desc "all", "run all tests"
def all
exec "rspec --color --format=documentation spec"
end
desc "unit", "run only unit tests"
def unit
exec "rspec --color --format=documentation spec --tag ~type:acceptance"
end
desc "acceptance", "run only acceptance tests"
def acceptance
exec "rspec --color --format=documentation spec --tag type:acceptance"
end
end
end
ridley-5.1.1/Rakefile 0000644 0000041 0000041 00000000034 13123557300 014477 0 ustar www-data www-data require 'bundler/gem_tasks'
ridley-5.1.1/.gitattributes 0000644 0000041 0000041 00000000123 13123557300 015724 0 ustar www-data www-data * text=auto
*.h text eol=lf
*.erb text eol=lf
*.txt text eol=lf
*.json text eol=lf
ridley-5.1.1/Gemfile 0000644 0000041 0000041 00000002144 13123557300 014331 0 ustar www-data www-data source 'https://rubygems.org'
gemspec
platforms :jruby do
gem 'jruby-openssl'
end
group :development do
gem 'yard'
gem 'spork'
gem 'guard', '>= 1.5.0'
gem 'guard-yard'
gem 'guard-rspec'
gem 'guard-spork', platforms: :ruby
gem 'coolline'
gem 'redcarpet', platforms: :ruby
gem 'kramdown', platforms: :jruby
require 'rbconfig'
if RbConfig::CONFIG['target_os'] =~ /darwin/i
gem 'growl', require: false
gem 'rb-fsevent', require: false
if `uname`.strip == 'Darwin' && `sw_vers -productVersion`.strip >= '10.8'
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
end rescue Errno::ENOENT
elsif RbConfig::CONFIG['target_os'] =~ /linux/i
gem 'libnotify', '~> 0.8.0', require: false
gem 'rb-inotify', require: false
elsif RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
gem 'win32console', require: false
gem 'rb-notifu', '>= 0.0.4', require: false
gem 'wdm', require: false
end
end
group :test do
gem 'thor'
gem 'rake', '>= 0.9.2.2'
gem 'rspec', '~> 3.0'
gem 'fuubar'
gem 'json_spec'
gem 'webmock'
gem 'chef-zero', '~> 1.5.0'
end
ridley-5.1.1/appveyor.yml 0000644 0000041 0000041 00000001654 13123557300 015433 0 ustar www-data www-data version: "master-{build}"
os: Windows Server 2012 R2
platform:
- x64
environment:
matrix:
- ruby_version: "23-x64"
- ruby_version: "23"
clone_depth: 1
skip_tags: true
skip_branch_with_pr: true
branches:
only:
- master
install:
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
- ruby --version
- gem update --system || gem update --system || gem update --system
- gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc
- update_rubygems
- gem --version
- bundler --version
- SET BUNDLE_IGNORE_CONFIG=true
- SET CI=true
- SET BUNDLE_WITHOUT=development:guard:maintenance:tools:integration:changelog:docgen:travis:style:omnibus_package:aix:bsd:linux:mac_os_x:solaris
build_script:
- bundle install || bundle install || bundle install
test_script:
- SET SPEC_OPTS=--format progress
- bundle exec thor spec:all
ridley-5.1.1/ridley.gemspec 0000644 0000041 0000041 00000003201 13123557300 015666 0 ustar www-data www-data # -*- encoding: utf-8 -*-
require File.expand_path('../lib/ridley/version', __FILE__)
Gem::Specification.new do |s|
s.authors = ["Jamie Winsor", "Kyle Allan"]
s.email = ["jamie@vialstudios.com", "kallan@riotgames.com"]
s.description = %q{A reliable Chef API client with a clean syntax}
s.summary = s.description
s.homepage = "https://github.com/berkshelf/ridley"
s.license = "Apache 2.0"
s.files = `git ls-files`.split($\)
s.executables = Array.new
s.test_files = s.files.grep(%r{^(spec)/})
s.name = "ridley"
s.require_paths = ["lib"]
s.version = Ridley::VERSION
s.required_ruby_version = ">= 2.2"
s.add_dependency 'addressable'
s.add_dependency 'varia_model', '~> 0.6'
s.add_dependency 'buff-config', '~> 2.0'
s.add_dependency 'buff-extensions', '~> 2.0'
s.add_dependency 'buff-ignore', '~> 1.2'
s.add_dependency 'buff-shell_out', '~> 1.0'
s.add_dependency 'celluloid', '~> 0.16.0'
s.add_dependency 'celluloid-io', '~> 0.16.1'
s.add_dependency 'chef-config', '>= 12.5.0'
s.add_dependency 'erubis'
s.add_dependency 'faraday', '~> 0.9'
s.add_dependency 'hashie', '>= 2.0.2', '< 4.0.0'
s.add_dependency 'httpclient', '~> 2.7'
s.add_dependency 'json', '>= 1.7.7'
s.add_dependency 'mixlib-authentication', '>= 1.3.0'
s.add_dependency 'retryable', '~> 2.0'
s.add_dependency 'semverse', '~> 2.0'
s.add_development_dependency 'buff-ruby_engine', '~> 0.1'
end
ridley-5.1.1/spec/ 0000755 0000041 0000041 00000000000 13123557300 013767 5 ustar www-data www-data ridley-5.1.1/spec/spec_helper.rb 0000644 0000041 0000041 00000002230 13123557300 016602 0 ustar www-data www-data require 'rubygems'
require 'bundler'
require 'buff/ruby_engine'
def setup_rspec
require 'rspec'
require 'json_spec'
require 'webmock/rspec'
Dir[File.join(File.expand_path("../../spec/support/**/*.rb", __FILE__))].each { |f| require f }
RSpec.configure do |config|
config.include Ridley::SpecHelpers
config.include Ridley::RSpec::ChefServer
config.include JsonSpec::Helpers
config.mock_with :rspec
config.treat_symbols_as_metadata_keys_with_true_values = true
config.filter_run focus: true
config.run_all_when_everything_filtered = true
config.before(:suite) do
WebMock.disable_net_connect!(allow_localhost: true, net_http_connect_on_start: true)
Ridley::RSpec::ChefServer.start
end
config.before(:all) { Ridley.logger = Celluloid.logger = nil }
config.before(:each) do
Celluloid.shutdown
Celluloid.boot
clean_tmp_path
Ridley::RSpec::ChefServer.server.clear_data
end
end
end
if Buff::RubyEngine.mri? && ENV['CI'] != 'true'
require 'spork'
Spork.prefork do
setup_rspec
end
Spork.each_run do
require 'ridley'
end
else
require 'ridley'
setup_rspec
end
ridley-5.1.1/spec/fixtures/ 0000755 0000041 0000041 00000000000 13123557300 015640 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/reset.pem 0000644 0000041 0000041 00000003217 13123557300 017470 0 ustar www-data www-data -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyyUMqrTh1IzKOyE0fvXEWC7m0AdMI8/dr9JJMUKtK9vhhP0w
rm6m95GoybFM2IRryukFsAxpcir3M1ungTU3Smq4MshhMJ7H9FbvZVfQoknTbCsR
w6scg2fBepxT2+fcGRufr8nAh92M3uUkN9bMMTAkt18D4br6035YvdmvHDJERxYq
ByA/720AdI9VNSIvw+x8oqsIkXLEdF6dgT9MpG5iWZT66pbFsnNZpRrd4/bFNWBY
+13aOqdmjiTL08/EdgQFKMT5qimpos1TuQhA7mwInOjQgzVu9uCDkMiYejaLbUz0
lGyS8y4uxu6z2hA900Jg/z+JJuXymH5QAX3GZQIDAQABAoIBAQCtFXkwbYPI1Nht
/wG6du5+8B9K+hy+mppY9wPTy+q+Zs9Ev3Fd/fuXDm1QxBckl9c8AMUO1dR2KPOM
t7gFl/DvH/SnmCFvCqp1nijFIUgrLlnMXPn6zG0z7RBlxpKQ2IGohufNIEpBuNwR
Ag2U4hgChPGTp4ooJ2cVEh7MS5AupYPDbC62dWEdW68aRTWhh2BCGAWBb6s16yl9
aZ7+OcxW2eeRJVbRfLkLQEDutJZi5TfOEn5QPc86ZgxcCmnvwulnpnhpz6QCkgQt
OP/+KRqDhWSDVCFREVT30fUIj1EWvK7NFWASZQxueZStuIvMEKeFebYfrbHxRFzJ
UmaxJnWVAoGBAPbKLpeky6ClccBaHHrCgjzakoDfGgyNKDQ9g753lJxB8nn7d9X4
HQpkWpfqAGFRZp1hI2H+VxyUXLh2Ob5OUeTm0OZJll35vycOaQEtfgIScXTcvzn0
16J9eX2YY4wIHEEMh85nKk8BEGgiNP5nuEviHocCeYXoi/Zq3+qj6v63AoGBANK5
4nyi6LBQFs1CUc7Sh7vjtOE3ia7KeRmOr7gS6QhS3iK3Oa8FzBLJ6ETjN2a9Bw8N
cF7I/+cr4s7DUJjxdb53D/J6TVSYORNNCUVnpF/uB2LqqdXDYmpO0PvFkXFoYTnJ
kaLAN8uCoLKr6JH9tq3DfXIfDIHiZ+BOIvI070fDAoGBAMDyzEDFmGruTyRLj66u
+rJnVVmqlKwxhLhrS+CTj74nlVOnt0a0KMhiM65IRqnPwcHUG5zXBPaUTHXwAS93
/nFPwQ37hLPOupPnoVNJZRZrowbyPBQtCJbDMURv64ylHqoBCQDoCd0hANnZvMMX
BrFVhfaaibaXXS542r6SD/27AoGAECadHE5kJTdOOBcwK/jo3Fa8g1J9Y/8yvum3
wBT69V9clS6T5j08geglvDnqAh7UzquKBEnFi1NKw+wmXkKLcrivaTdEfApavYb3
AfHKoGue907jC3Y5Mcquq81ds2J7qTEwz1eKLzfo1yjj32ShvrmwALIuhDn1GjUC
6qtx938CgYEApEqvu0nocR1jmVVlLe5uKQBj949dh6NGq0R5Lztz6xufaTYzMC3d
AZG9XPPjRqSLs+ylSXJpwHEwoeyLFDaJcO+GgW1/ut4MC2HppOx6aImwDdXMHUWR
KYGIFF4AU/IYoBcanAm4s078EH/Oz01B2c7tR2TqabisPgLYe7PXSCw=
-----END RSA PRIVATE KEY-----
ridley-5.1.1/spec/fixtures/recipe_two.rb 0000644 0000041 0000041 00000000014 13123557300 020320 0 ustar www-data www-data testfile two ridley-5.1.1/spec/fixtures/recipe_one.rb 0000644 0000041 0000041 00000000010 13123557300 020264 0 ustar www-data www-data testfile ridley-5.1.1/spec/fixtures/chefignore 0000644 0000041 0000041 00000000057 13123557300 017676 0 ustar www-data www-data README.md
Guardfile
ignores/*.rb
ignores/*.erb
ridley-5.1.1/spec/fixtures/encrypted_data_bag_secret 0000644 0000041 0000041 00000001254 13123557300 022731 0 ustar www-data www-data NTE5C5gzbe3F7fGBlrT/YTuMQuHlxaOWhY81KsgYXJ0mzDsDMFvCpfi4CUXu5M7n/Umgsf8jdHw/IIkJLZcXgk+Ll75kDU/VI5FyRzib0U0SX4JB8JLM7wRFgRpuk3GD27LnYR1APmLncE7R6ZSJc6iaFHcEL2MdR+hv0nhUZPUqITxYHyrYvqNSfroyxldQ/cvnrIMBS8JrpjIsLdYhcgL6mPJiakl4fM36cFk6Wl2Mxw7vOvGXRSR5l+t42pGDhtOjE3os5reLVoWkYoiQ1fpx3NrOdxsVuz17+3jMLBlmni2SGf2wncui2r9PqCrVbUbaCi6aNV1+SRbeh5kxBxjWSzw59BNXtna4vSK6hFPsT6tfXlOi67Q2vwjjAqltAVStGas/VZyU7DRzxMkbnPPtue+7Pajqe/TfSNWA5SX2cHtkG2X3EqZ8ftOa9p+b/VJlUnnnV2ilVfgjCW2q6XXMbC0C5yIbrDZm+aCJyhueA0j+ZHWM4k07OAuB7FRcuJJBs8H2StEx2o22OdAYUBcN5PRGlOAEBemL+sZAztbex2NjjOYV90806UFvSJLPixVWJgDTSA5OvXtNvUQYDYSGRQ/BmH86aA5gJ60AM9vEVB0BfPi946m9D4LZ/2uK6fqq3zVIV1s0EgfYHYUVz0oaf3srofc5YUAP3Ge/VLE= ridley-5.1.1/spec/fixtures/example_cookbook/ 0000755 0000041 0000041 00000000000 13123557300 021161 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/definitions/ 0000755 0000041 0000041 00000000000 13123557300 023474 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/definitions/bad_def.rb 0000644 0000041 0000041 00000000154 13123557300 025365 0 ustar www-data www-data # Definition: bad_def
#
# Copyright 2012, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
ridley-5.1.1/spec/fixtures/example_cookbook/files/ 0000755 0000041 0000041 00000000000 13123557300 022263 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/files/default/ 0000755 0000041 0000041 00000000000 13123557300 023707 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/files/default/file.h 0000644 0000041 0000041 00000000017 13123557300 024775 0 ustar www-data www-data # file.h
hello
ridley-5.1.1/spec/fixtures/example_cookbook/files/ubuntu/ 0000755 0000041 0000041 00000000000 13123557300 023605 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/files/ubuntu/file.h 0000644 0000041 0000041 00000000027 13123557300 024674 0 ustar www-data www-data # file.h
hello, ubuntu
ridley-5.1.1/spec/fixtures/example_cookbook/resources/ 0000755 0000041 0000041 00000000000 13123557300 023173 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/resources/defresource.rb 0000644 0000041 0000041 00000000156 13123557300 026030 0 ustar www-data www-data # Resource: defresource
#
# Copyright 2012, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
ridley-5.1.1/spec/fixtures/example_cookbook/templates/ 0000755 0000041 0000041 00000000000 13123557300 023157 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/templates/default/ 0000755 0000041 0000041 00000000000 13123557300 024603 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/templates/default/temp.txt.erb 0000644 0000041 0000041 00000000016 13123557300 027055 0 ustar www-data www-data <%= 'hello' %> ridley-5.1.1/spec/fixtures/example_cookbook/metadata.rb 0000644 0000041 0000041 00000001055 13123557300 023267 0 ustar www-data www-data name "example_cookbook"
maintainer "Jamie Winsor"
maintainer_email "jamie@vialstudios.com"
license "Apache 2.0"
description "Installs/Configures example_cookbook"
long_description IO.read(File.join(File.dirname(__FILE__), "README.md"))
version "0.1.0"
attribute "example_cookbook/test",
:display_name => "Test",
:description => "Test Attribute",
:choice => [
"test1",
"test2" ],
:type => "string",
:required => "recommended",
:recipes => [ 'example_cookbook::default' ],
:default => "test1"
ridley-5.1.1/spec/fixtures/example_cookbook/providers/ 0000755 0000041 0000041 00000000000 13123557300 023176 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/providers/defprovider.rb 0000644 0000041 0000041 00000000156 13123557300 026036 0 ustar www-data www-data # Provider: defprovider
#
# Copyright 2012, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
ridley-5.1.1/spec/fixtures/example_cookbook/attributes/ 0000755 0000041 0000041 00000000000 13123557300 023347 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/attributes/default.rb 0000644 0000041 0000041 00000000154 13123557300 025320 0 ustar www-data www-data # Attribute:: default
#
# Copyright 2012, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
ridley-5.1.1/spec/fixtures/example_cookbook/libraries/ 0000755 0000041 0000041 00000000000 13123557300 023135 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/libraries/my_lib.rb 0000644 0000041 0000041 00000000150 13123557300 024731 0 ustar www-data www-data # Library: my_lib
#
# Copyright 2012, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
ridley-5.1.1/spec/fixtures/example_cookbook/README.md 0000644 0000041 0000041 00000000127 13123557300 022440 0 ustar www-data www-data Description
===========
Requirements
============
Attributes
==========
Usage
=====
ridley-5.1.1/spec/fixtures/example_cookbook/Guardfile 0000644 0000041 0000041 00000000047 13123557300 023007 0 ustar www-data www-data # This should be ignored by chefignore
ridley-5.1.1/spec/fixtures/example_cookbook/ignores/ 0000755 0000041 0000041 00000000000 13123557300 022627 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/ignores/magic.rb 0000644 0000041 0000041 00000000117 13123557300 024233 0 ustar www-data www-data # I should never see this file
# It has bad ruby in it...
this is not { valid
ridley-5.1.1/spec/fixtures/example_cookbook/ignores/magic.erb 0000644 0000041 0000041 00000000126 13123557300 024400 0 ustar www-data www-data # I should never see this file
# It has bad ruby in it...
<%= this is not { valid %>
ridley-5.1.1/spec/fixtures/example_cookbook/ignores/ok.txt 0000644 0000041 0000041 00000000031 13123557300 023773 0 ustar www-data www-data This one is okay, though
ridley-5.1.1/spec/fixtures/example_cookbook/recipes/ 0000755 0000041 0000041 00000000000 13123557300 022613 5 ustar www-data www-data ridley-5.1.1/spec/fixtures/example_cookbook/recipes/default.rb 0000644 0000041 0000041 00000000150 13123557300 024560 0 ustar www-data www-data # Recipe: default
#
# Copyright 2012, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
ridley-5.1.1/spec/unit/ 0000755 0000041 0000041 00000000000 13123557300 014746 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley_spec.rb 0000644 0000041 0000041 00000006133 13123557300 017600 0 ustar www-data www-data require 'spec_helper'
describe Ridley do
let(:config) { double("config") }
describe "ClassMethods" do
subject { Ridley }
describe "::new" do
it "creates a new Ridley::Connection" do
client = double('client')
expect(Ridley::Client).to receive(:new).with(config).and_return(client)
expect(subject.new(config)).to eql(client)
end
end
describe "from_chef_config" do
let(:chef_config) do
%(
node_name "username"
client_key "username.pem"
validation_client_name "validator"
validation_key "validator.pem"
chef_server_url "https://api.opscode.com"
cache_options(:path => "~/.chef/checksums")
syntax_check_cache_path "/foo/bar"
ssl_verify_mode :verify_none
)
end
let(:client) { double('client') }
let(:path) { tmp_path.join('config.rb').to_s }
before do
allow(Ridley::Client).to receive(:new).and_return(client)
File.open(path, 'w') { |f| f.write(chef_config) }
end
it "creates a Ridley connection from the Chef config" do
expect(Ridley::Client).to receive(:new).with(hash_including(
client_key: 'username.pem',
client_name: 'username',
validator_client: 'validator',
validator_path: 'validator.pem',
server_url: 'https://api.opscode.com',
syntax_check_cache_path: "/foo/bar",
cache_options: { path: "~/.chef/checksums" },
ssl: {verify: false},
)).and_return(nil)
subject.from_chef_config(path)
end
it "allows the user to override attributes" do
expect(Ridley::Client).to receive(:new).with(hash_including(
client_key: 'bacon.pem',
client_name: 'bacon',
validator_client: 'validator',
validator_path: 'validator.pem',
server_url: 'https://api.opscode.com',
syntax_check_cache_path: "/foo/bar",
cache_options: { path: "~/.chef/checksums" },
ssl: {verify: false},
))
subject.from_chef_config(path, client_key: 'bacon.pem', client_name: 'bacon')
end
context "when the config location isn't explicitly specified" do
before do
dot_chef = tmp_path.join('.chef')
knife_rb = dot_chef.join('knife.rb')
FileUtils.mkdir_p(dot_chef)
File.open(knife_rb, 'w') { |f| f.write(chef_config) }
end
it "does a knife.rb search" do
expect(Ridley::Client).to receive(:new).with(hash_including(
client_key: 'username.pem',
client_name: 'username',
validator_client: 'validator',
validator_path: 'validator.pem',
server_url: 'https://api.opscode.com',
syntax_check_cache_path: "/foo/bar",
cache_options: { path: "~/.chef/checksums" },
)).and_return(nil)
Dir.chdir(tmp_path) do
ENV['PWD'] = Dir.pwd
subject.from_chef_config
end
end
end
end
end
end
ridley-5.1.1/spec/unit/ridley/ 0000755 0000041 0000041 00000000000 13123557300 016236 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/middleware/ 0000755 0000041 0000041 00000000000 13123557300 020353 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/middleware/chef_response_spec.rb 0000644 0000041 0000041 00000013365 13123557300 024545 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Middleware::ChefResponse do
let(:server_url) { "https://api.opscode.com/organizations/vialstudios/" }
describe "ClassMethods" do
subject { Ridley::Middleware::ChefResponse }
describe "::success?" do
let(:env) { double('env') }
it "returns true if response status between 200 and 210" do
(200..210).each do |code|
expect(env).to receive(:[]).with(:status).and_return(code)
expect(subject.success?(env)).to be_truthy
end
end
it "returns false if response status is in the 300 range" do
(300..399).each do |code|
expect(env).to receive(:[]).with(:status).and_return(code)
expect(subject.success?(env)).to be_falsey
end
end
it "returns false if response status is in the 400 range" do
(400..499).each do |code|
expect(env).to receive(:[]).with(:status).and_return(code)
expect(subject.success?(env)).to be_falsey
end
end
it "returns false if response status is in the 500 range" do
(500..599).each do |code|
expect(env).to receive(:[]).with(:status).and_return(code)
expect(subject.success?(env)).to be_falsey
end
end
end
end
subject do
Faraday.new(server_url) do |conn|
conn.response :chef_response
conn.response :parse_json
conn.adapter Faraday.default_adapter
end
end
let(:chef_ok) do
{
status: 200,
body: generate_normalized_json(name: "reset-role", description: "a new role"),
headers: {
content_type: "application/json; charset=utf8"
}
}
end
let(:chef_bad_request) do
{
status: 400,
body: generate_normalized_json(error: "400 - Bad Request: Valid X-CHEF-VERSION header is required."),
headers: {
content_type: "application/json; charset=utf8"
}
}
end
let(:chef_unauthorized) do
{
status: 401,
body: generate_normalized_json(error: "401 - Unauthorized. You must properly authenticate your API requests!"),
headers: {
content_type: "application/json; charset=utf8"
}
}
end
let(:chef_forbidden) do
{
status: 403,
body: generate_normalized_json(error: "403 - Forbidden."),
headers: {
content_type: "application/json; charset=utf8"
}
}
end
let(:chef_not_found) do
{
status: 404,
body: generate_normalized_json(error: [ "No routes match the request: /organizations/vialstudios/cookbookss/not_existant" ]),
headers: {
content_type: "application/json; charset=utf8"
}
}
end
let(:chef_conflict) do
{
status: 409,
body: generate_normalized_json(error: "409 - Conflict."),
headers: {
content_type: "application/json; charset=utf8"
}
}
end
describe "400 Bad Request" do
before(:each) do
stub_request(:get, File.join(server_url, 'cookbooks')).to_return(chef_bad_request)
end
it "raises a Ridley::Errors::HTTPBadRequest" do
expect {
subject.get('cookbooks')
}.to raise_error(Ridley::Errors::HTTPBadRequest)
end
it "should have the body of the response as the error's message" do
expect {
subject.get('cookbooks')
}.to raise_error("errors: '400 - Bad Request: Valid X-CHEF-VERSION header is required.'")
end
end
describe "401 Unauthorized" do
before(:each) do
stub_request(:get, File.join(server_url, 'cookbooks')).to_return(chef_unauthorized)
end
it "raises a Ridley::Errors::HTTPUnauthorized" do
expect {
subject.get('cookbooks')
}.to raise_error(Ridley::Errors::HTTPUnauthorized)
end
it "should have the body of the response as the error's message" do
expect {
subject.get('cookbooks')
}.to raise_error("errors: '401 - Unauthorized. You must properly authenticate your API requests!'")
end
end
describe "403 Forbidden" do
before(:each) do
stub_request(:get, File.join(server_url, 'cookbooks')).to_return(chef_forbidden)
end
it "raises a Ridley::Errors::HTTPForbidden" do
expect {
subject.get('cookbooks')
}.to raise_error(Ridley::Errors::HTTPForbidden)
end
it "should have the body of the response as the error's message" do
expect {
subject.get('cookbooks')
}.to raise_error("errors: '403 - Forbidden.'")
end
end
describe "404 Not Found" do
before(:each) do
stub_request(:get, File.join(server_url, 'not_existant_route')).to_return(chef_not_found)
end
it "raises a Ridley::Errors::HTTPNotFound" do
expect {
subject.get('not_existant_route')
}.to raise_error(Ridley::Errors::HTTPNotFound)
end
it "should have the body of the response as the error's message" do
expect {
subject.get('not_existant_route')
}.to raise_error(Ridley::Errors::HTTPNotFound, "errors: 'No routes match the request: /organizations/vialstudios/cookbookss/not_existant'")
end
end
describe "409 Conflict" do
before(:each) do
stub_request(:get, File.join(server_url, 'cookbooks')).to_return(chef_conflict)
end
it "raises a Ridley::Errors::HTTPForbidden" do
expect {
subject.get('cookbooks')
}.to raise_error(Ridley::Errors::HTTPConflict)
end
it "should have the body of the response as the error's message" do
expect {
subject.get('cookbooks')
}.to raise_error("errors: '409 - Conflict.'")
end
end
describe "200 OK" do
before(:each) do
stub_request(:get, File.join(server_url, 'roles/reset')).to_return(chef_ok)
end
it "returns a body containing a hash" do
expect(subject.get('roles/reset').env[:body]).to be_a(Hash)
end
end
end
ridley-5.1.1/spec/unit/ridley/middleware/chef_auth_spec.rb 0000644 0000041 0000041 00000002412 13123557300 023637 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Middleware::ChefAuth do
let(:server_url) { "https://api.opscode.com/organizations/vialstudios/" }
describe "ClassMethods" do
subject { described_class }
describe "#authentication_headers" do
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join("reset.pem") }
it "returns a Hash of authentication headers" do
options = {
http_method: "GET",
host: "https://api.opscode.com",
path: "/something.file"
}
expect(subject.authentication_headers(client_name, client_key, options)).to be_a(Hash)
end
context "when the :client_key is an actual key" do
let(:client_key) { File.read(fixtures_path.join("reset.pem")) }
it "returns a Hash of authentication headers" do
options = {
http_method: "GET",
host: "https://api.opscode.com",
path: "/something.file"
}
expect(subject.authentication_headers(client_name, client_key, options)).to be_a(Hash)
end
end
end
end
subject do
Faraday.new(server_url) do |conn|
conn.request :chef_auth, "reset", "/Users/reset/.chef/reset.pem"
conn.adapter Faraday.default_adapter
end
end
end
ridley-5.1.1/spec/unit/ridley/middleware/parse_json_spec.rb 0000644 0000041 0000041 00000004636 13123557300 024066 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Middleware::ParseJson do
let(:server_url) { "https://api.opscode.com/organizations/vialstudios/" }
describe "ClassMethods" do
subject { Ridley::Middleware::ParseJson }
describe "::response_type" do
it "returns the first element of the response content-type" do
env = double('env')
allow(env).to receive(:[]).with(:response_headers).and_return(
'content-type' => 'text/html; charset=utf-8'
)
expect(subject.response_type(env)).to eql("text/html")
end
end
describe "::json_response?" do
it "returns true if the value of content-type includes 'application/json' and the body looks like JSON" do
env = double('env')
allow(env).to receive(:[]).with(:response_headers).and_return(
'content-type' => 'application/json; charset=utf8'
)
expect(subject).to receive(:looks_like_json?).with(env).and_return(true)
expect(subject.json_response?(env)).to be_truthy
end
it "returns false if the value of content-type includes 'application/json' but the body does not look like JSON" do
env = double('env')
allow(env).to receive(:[]).with(:response_headers).and_return(
'content-type' => 'application/json; charset=utf8'
)
expect(subject).to receive(:looks_like_json?).with(env).and_return(false)
expect(subject.json_response?(env)).to be_falsey
end
it "returns false if the value of content-type does not include 'application/json'" do
env = double('env')
allow(env).to receive(:[]).with(:response_headers).and_return(
'content-type' => 'text/plain'
)
expect(subject.json_response?(env)).to be_falsey
end
end
describe "::looks_like_json?" do
let(:env) { double('env') }
it "returns true if the given string contains JSON brackets" do
allow(env).to receive(:[]).with(:body).and_return("{\"name\":\"jamie\"}")
expect(subject.looks_like_json?(env)).to be_truthy
end
it "returns false if the given string does not contain JSON brackets" do
allow(env).to receive(:[]).with(:body).and_return("name")
expect(subject.looks_like_json?(env)).to be_falsey
end
end
end
subject do
Faraday.new(server_url) do |conn|
conn.response :json
conn.adapter Faraday.default_adapter
end
end
end
ridley-5.1.1/spec/unit/ridley/resource_spec.rb 0000644 0000041 0000041 00000010220 13123557300 021417 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Resource do
let(:representation) do
Class.new(Ridley::ChefObject) do
set_chef_id "id"
set_chef_type "thing"
set_chef_json_class "Chef::Thing"
end
end
let(:resource_class) do
Class.new(Ridley::Resource) do
set_resource_path "rspecs"
end
end
describe "ClassMethods" do
subject { resource_class }
describe "::set_resource_path" do
it "sets the resource_path attr on the class" do
subject.set_resource_path("environments")
expect(subject.resource_path).to eql("environments")
end
end
describe "::resource_path" do
context "when not explicitly set" do
before { subject.set_resource_path(nil) }
it "returns the representation's chef type" do
expect(subject.resource_path).to eql(representation.chef_type)
end
end
context "when explicitly set" do
let(:set_path) { "hello" }
before { subject.set_resource_path(set_path) }
it "returns the set value" do
expect(subject.resource_path).to eql(set_path)
end
end
end
end
let(:connection) { double('chef-connection') }
let(:response) { double('chef-response', body: Hash.new) }
let(:resource_json) { '{"some":"valid json"}' }
subject { resource_class.new(double('registry')) }
before do
resource_class.stub(representation: representation)
subject.stub(connection: connection)
end
describe "::from_file" do
it "reads the file and calls ::from_json with contents" do
File.stub(:read) { resource_json }
subject.should_receive(:from_json).with(resource_json)
subject.from_file('/bogus/filename.json')
end
end
describe "::from_json" do
it "parses the argument and calls ::new with newly built hash" do
hashed_json = JSON.parse(resource_json)
subject.should_receive(:new).with(hashed_json).and_return representation
subject.from_json(resource_json)
end
end
describe "::all" do
it "sends GET to /{resource_path}" do
connection.should_receive(:get).with(subject.class.resource_path).and_return(response)
subject.all
end
end
describe "::find" do
let(:id) { "some_id" }
it "sends GET to /{resource_path}/{id} where {id} is the given ID" do
connection.should_receive(:get).with("#{subject.class.resource_path}/#{id}").and_return(response)
subject.find(id)
end
context "when the resource is not found" do
before do
connection.should_receive(:get).with("#{subject.class.resource_path}/#{id}").
and_raise(Ridley::Errors::HTTPNotFound.new({}))
end
it "returns nil" do
expect(subject.find(id)).to be_nil
end
end
end
describe "::create" do
let(:attrs) do
{
first_name: "jamie",
last_name: "winsor"
}
end
it "sends a post request to the given client using the includer's resource_path" do
connection.should_receive(:post).with(subject.class.resource_path, duck_type(:to_json)).and_return(response)
subject.create(attrs)
end
end
describe "::delete" do
it "sends a delete request to the given client using the includer's resource_path for the given string" do
connection.should_receive(:delete).with("#{subject.class.resource_path}/ridley-test").and_return(response)
subject.delete("ridley-test")
end
it "accepts an object that responds to 'chef_id'" do
object = double("obj")
object.stub(:chef_id) { "hello" }
connection.should_receive(:delete).with("#{subject.class.resource_path}/#{object.chef_id}").and_return(response)
subject.delete( object)
end
end
describe "::delete_all" do
it "sends a delete request for every object in the collection" do
skip
end
end
describe "::update" do
it "sends a put request to the given client using the includer's resource_path with the given object" do
object = subject.new(name: "hello")
connection.should_receive(:put).
with("#{subject.class.resource_path}/#{object.chef_id}", duck_type(:to_json)).and_return(response)
subject.update(object)
end
end
end
ridley-5.1.1/spec/unit/ridley/mixins/ 0000755 0000041 0000041 00000000000 13123557300 017545 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/mixins/from_file_spec.rb 0000644 0000041 0000041 00000001735 13123557300 023054 0 ustar www-data www-data require 'spec_helper'
module Ridley
describe Mixin::FromFile do
describe '.from_file' do
context 'when there is bad Ruby in the file' do
let(:instance) { Class.new { include Ridley::Mixin::FromFile }.new }
before do
allow(File).to receive(:exists?).and_return(true)
allow(File).to receive(:readable?).and_return(true)
allow(IO).to receive(:read).and_return('invalid Ruby code')
end
it 'raises a FromFileParserError' do
expect {
instance.from_file('/path')
}.to raise_error(Errors::FromFileParserError)
end
it 'includes the backtrace from the original error' do
expect { instance.from_file('/path') }.to raise_error { |error|
expect(error.message).to include("undefined local variable or method `code' for")
expect(error.backtrace).to include("/path:1:in `block in from_file'")
}
end
end
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/ 0000755 0000041 0000041 00000000000 13123557300 020654 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/chef_objects/client_object_spec.rb 0000644 0000041 0000041 00000000224 13123557300 025015 0 ustar www-data www-data require 'spec_helper'
describe Ridley::ClientObject do
describe "#to_json" do
skip
end
describe "#regenerate_key" do
skip
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/environment_object_spec.rb 0000644 0000041 0000041 00000007650 13123557300 026115 0 ustar www-data www-data require 'spec_helper'
describe Ridley::EnvironmentObject do
subject { described_class.new(double('registry')) }
describe "#set_override_attribute" do
it "sets an override node attribute at the nested path" do
subject.set_override_attribute('deep.nested.item', true)
expect(subject.override_attributes).to have_key("deep")
expect(subject.override_attributes["deep"]).to have_key("nested")
expect(subject.override_attributes["deep"]["nested"]).to have_key("item")
expect(subject.override_attributes["deep"]["nested"]["item"]).to be_truthy
end
context "when the override attribute is already set" do
it "test" do
subject.override_attributes = {
deep: {
nested: {
item: false
}
}
}
subject.set_override_attribute('deep.nested.item', true)
expect(subject.override_attributes["deep"]["nested"]["item"]).to be_truthy
end
end
end
describe "#set_default_attribute" do
it "sets an override node attribute at the nested path" do
subject.set_default_attribute('deep.nested.item', true)
expect(subject.default_attributes).to have_key("deep")
expect(subject.default_attributes["deep"]).to have_key("nested")
expect(subject.default_attributes["deep"]["nested"]).to have_key("item")
expect(subject.default_attributes["deep"]["nested"]["item"]).to be_truthy
end
context "when the override attribute is already set" do
it "test" do
subject.default_attributes = {
deep: {
nested: {
item: false
}
}
}
subject.set_default_attribute('deep.nested.item', true)
expect(subject.default_attributes["deep"]["nested"]["item"]).to be_truthy
end
end
shared_examples_for "attribute deleter" do
let(:precedence) { raise "You must provide the precedence level (let(:precedence) { \"default\" } in the shared example context" }
let(:delete_attribute) { subject.send(:"delete_#{precedence}_attribute", delete_attribute_key) }
let(:set_attribute_value) { true }
let(:attributes) { { "hello" => { "world" => set_attribute_value } } }
let(:delete_attribute_key) { "hello.world" }
before do
subject.send(:"#{precedence}_attributes=", attributes)
end
it "removes the attribute" do
delete_attribute
expect(subject.send(:"#{precedence}_attributes")[:hello][:world]).to be_nil
end
context "when the attribute does not exist" do
let(:delete_attribute_key) { "not.existing" }
it "does not delete anything" do
delete_attribute
expect(subject.send(:"#{precedence}_attributes")[:hello][:world]).to eq(set_attribute_value)
end
end
context "when an internal hash is nil" do
let(:delete_attribute_key) { "never.not.existing" }
before do
subject.send(:"#{precedence}_attributes=", Hash.new)
end
it "does not delete anything" do
delete_attribute
expect(subject.send(:"#{precedence}_attributes")).to be_empty
end
end
["string", true, :symbol, ["array"], Object.new].each do |nonattrs|
context "when the attribute chain is partially set, interrupted by a #{nonattrs.class}" do
let(:attributes) { { "hello" => set_attribute_value } }
let(:set_attribute_value) { nonattrs }
it "leaves the attributes unchanged" do
expect(subject.send(:"unset_#{precedence}_attribute", delete_attribute_key).to_hash).to eq(attributes)
end
end
end
end
describe "#delete_default_attribute" do
it_behaves_like "attribute deleter" do
let(:precedence) { "default" }
end
end
describe "#delete_override_attribute" do
it_behaves_like "attribute deleter" do
let(:precedence) { "override" }
end
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/data_bag_object_spec.rb 0000644 0000041 0000041 00000000546 13123557300 025270 0 ustar www-data www-data require 'spec_helper'
describe Ridley::DataBagObject do
let(:item_resource) { double('item-resource') }
let(:resource) { double('db-resource', item_resource: item_resource) }
subject { described_class.new(resource) }
describe '#item' do
subject { super().item }
it { is_expected.to be_a(Ridley::DataBagObject::DataBagItemProxy) }
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/node_object_spec.rb 0000644 0000041 0000041 00000021242 13123557300 024467 0 ustar www-data www-data require 'spec_helper'
describe Ridley::NodeObject do
let(:resource) { double('resource') }
let(:instance) { described_class.new(resource) }
subject { instance }
describe "#chef_attributes" do
subject { instance.chef_attributes }
it "returns a Hashie::Mash" do
expect(subject).to be_a(Hashie::Mash)
end
it "includes default attributes" do
instance.default = default = { "default" => { "one" => "val", "two" => "val" } }
expect(subject.to_hash).to include(default)
end
it "includes normal attributes" do
instance.normal = normal = { "normal" => { "one" => "val", "two" => "val" } }
expect(subject.to_hash).to include(normal)
end
it "includes override attributes" do
instance.override = override = { "override" => { "one" => "val", "two" => "val" } }
expect(subject.to_hash).to include(override)
end
it "includes automatic attributes" do
instance.automatic = automatic = { "automatic" => { "one" => "val", "two" => "val" } }
expect(subject.to_hash).to include(automatic)
end
it "overrides default attributes with normal attributes" do
instance.default = default = { one: "old", two: "old" }
instance.normal = normal = { one: "new" }
expect(subject[:one]).to eql("new")
expect(subject[:two]).to eql("old")
end
it "overrides normal attributes with override attributes" do
instance.normal = normal = { one: "old", two: "old" }
instance.override = override = { one: "new" }
expect(subject[:one]).to eql("new")
expect(subject[:two]).to eql("old")
end
it "overrides override attributes with automatic attributes" do
instance.override = override = { one: "old", two: "old" }
instance.automatic = automatic = { one: "new" }
expect(subject[:one]).to eql("new")
expect(subject[:two]).to eql("old")
end
end
describe "#set_chef_attribute" do
it "sets a normal node attribute at the nested path" do
subject.set_chef_attribute('deep.nested.item', true)
expect(subject.normal).to have_key("deep")
expect(subject.normal["deep"]).to have_key("nested")
expect(subject.normal["deep"]["nested"]).to have_key("item")
expect(subject.normal["deep"]["nested"]["item"]).to be_truthy
end
context "when the normal attribute is already set" do
it "test" do
subject.normal = {
deep: {
nested: {
item: false
}
}
}
subject.set_chef_attribute('deep.nested.item', true)
expect(subject.normal["deep"]["nested"]["item"]).to be_truthy
end
end
end
describe "#unset_chef_attribute" do
context "when the attribute is set" do
before do
subject.normal = { foo: { bar: { baz: true } } }
end
it "unsets a normal node attribute at the nested path" do
subject.unset_chef_attribute("foo.bar.baz")
expect(subject.normal[:foo][:bar][:baz]).to be_nil
end
end
["string", true, :symbol, ["array"], Object.new].each do |nonattrs|
context "when the attribute chain is partially set, interrupted by a #{nonattrs.class}" do
let(:attributes) { { 'foo' => { 'bar' => nonattrs } } }
before do
subject.normal = attributes
end
it "leaves the attributes unchanged" do
expect(subject.unset_chef_attribute("foo.bar.baz").to_hash).to eq(attributes)
end
end
end
context "when the attribute is not set" do
let(:attributes) { { 'bizz' => { 'bar' => { 'baz' => true } } } }
before do
subject.normal = attributes
end
it "leaves the attributes unchanged" do
expect(subject.unset_chef_attribute("foo.bar.baz").to_hash).to eq(attributes)
end
end
end
describe "#cloud?" do
it "returns true if the cloud automatic attribute is set" do
subject.automatic = {
"cloud" => Hash.new
}
expect(subject.cloud?).to be_truthy
end
it "returns false if the cloud automatic attribute is not set" do
subject.automatic.delete(:cloud)
expect(subject.cloud?).to be_falsey
end
end
describe "#eucalyptus?" do
it "returns true if the node is a cloud node using the eucalyptus provider" do
subject.automatic = {
"cloud" => {
"provider" => "eucalyptus"
}
}
expect(subject.eucalyptus?).to be_truthy
end
it "returns false if the node is not a cloud node" do
subject.automatic.delete(:cloud)
expect(subject.eucalyptus?).to be_falsey
end
it "returns false if the node is a cloud node but not using the eucalyptus provider" do
subject.automatic = {
"cloud" => {
"provider" => "ec2"
}
}
expect(subject.eucalyptus?).to be_falsey
end
end
describe "#ec2?" do
it "returns true if the node is a cloud node using the ec2 provider" do
subject.automatic = {
"cloud" => {
"provider" => "ec2"
}
}
expect(subject.ec2?).to be_truthy
end
it "returns false if the node is not a cloud node" do
subject.automatic.delete(:cloud)
expect(subject.ec2?).to be_falsey
end
it "returns false if the node is a cloud node but not using the ec2 provider" do
subject.automatic = {
"cloud" => {
"provider" => "rackspace"
}
}
expect(subject.ec2?).to be_falsey
end
end
describe "#rackspace?" do
it "returns true if the node is a cloud node using the rackspace provider" do
subject.automatic = {
"cloud" => {
"provider" => "rackspace"
}
}
expect(subject.rackspace?).to be_truthy
end
it "returns false if the node is not a cloud node" do
subject.automatic.delete(:cloud)
expect(subject.rackspace?).to be_falsey
end
it "returns false if the node is a cloud node but not using the rackspace provider" do
subject.automatic = {
"cloud" => {
"provider" => "ec2"
}
}
expect(subject.rackspace?).to be_falsey
end
end
describe "#cloud_provider" do
it "returns the cloud provider if the node is a cloud node" do
subject.automatic = {
"cloud" => {
"provider" => "ec2"
}
}
expect(subject.cloud_provider).to eql("ec2")
end
it "returns nil if the node is not a cloud node" do
subject.automatic.delete(:cloud)
expect(subject.cloud_provider).to be_nil
end
end
describe "#public_ipv4" do
it "returns the public ipv4 address if the node is a cloud node" do
subject.automatic = {
"cloud" => {
"provider" => "ec2",
"public_ipv4" => "10.0.0.1"
}
}
expect(subject.public_ipv4).to eql("10.0.0.1")
end
it "returns the ipaddress if the node is not a cloud node" do
subject.automatic = {
"ipaddress" => "192.168.1.1"
}
subject.automatic.delete(:cloud)
expect(subject.public_ipv4).to eql("192.168.1.1")
end
end
describe "#public_hostname" do
it "returns the public hostname if the node is a cloud node" do
subject.automatic = {
"cloud" => {
"public_hostname" => "reset.cloud.riotgames.com"
}
}
expect(subject.public_hostname).to eql("reset.cloud.riotgames.com")
end
it "returns the FQDN if the node is not a cloud node" do
subject.automatic = {
"fqdn" => "reset.internal.riotgames.com"
}
subject.automatic.delete(:cloud)
expect(subject.public_hostname).to eql("reset.internal.riotgames.com")
end
end
describe "#merge_data" do
before(:each) { subject.name = "reset.riotgames.com" }
it "appends items to the run_list" do
subject.merge_data(run_list: ["cook::one", "cook::two"])
expect(subject.run_list).to match_array(["cook::one", "cook::two"])
end
it "ensures the run_list is unique if identical items are given" do
subject.run_list = [ "cook::one" ]
subject.merge_data(run_list: ["cook::one", "cook::two"])
expect(subject.run_list).to match_array(["cook::one", "cook::two"])
end
it "deep merges attributes into the normal attributes" do
subject.normal = {
one: {
two: {
four: :deep
}
}
}
subject.merge_data(attributes: {
one: {
two: {
three: :deep
}
}
})
expect(subject.normal[:one][:two]).to have_key(:four)
expect(subject.normal[:one][:two][:four]).to eql(:deep)
expect(subject.normal[:one][:two]).to have_key(:three)
expect(subject.normal[:one][:two][:three]).to eql(:deep)
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/sandbox_object_spec.rb 0000644 0000041 0000041 00000003557 13123557300 025211 0 ustar www-data www-data require 'spec_helper'
describe Ridley::SandboxObject do
let(:resource) { double('chef-resource') }
subject do
described_class.new(double('registry'),
"uri" => "https://api.opscode.com/organizations/vialstudios/sandboxes/bd091b150b0a4578b97771af6abf3e05",
"checksums" => {
"385ea5490c86570c7de71070bce9384a" => {
"url" => "https://s3.amazonaws.com/opscode-platform-production-data/organization",
"needs_upload" => true
},
"f6f73175e979bd90af6184ec277f760c" => {
"url" => "https://s3.amazonaws.com/opscode-platform-production-data/organization",
"needs_upload" => true
},
"2e03dd7e5b2e6c8eab1cf41ac61396d5" => {
"url" => "https://s3.amazonaws.com/opscode-platform-production-data/organization",
"needs_upload" => true
},
},
"sandbox_id" => "bd091b150b0a4578b97771af6abf3e05"
)
end
before { allow(subject).to receive_messages(resource: resource) }
describe "#checksums" do
skip
end
describe "#commit" do
let(:response) { { is_completed: nil} }
before { expect(resource).to receive(:commit).with(subject).and_return(response) }
context "when the commit is successful" do
before { response[:is_completed] = true }
it "has an 'is_completed' value of true" do
subject.commit
expect(subject.is_completed).to be_truthy
end
end
context "when the commit is a failure" do
before { response[:is_completed] = false }
it "has an 'is_completed' value of false" do
subject.commit
expect(subject.is_completed).to be_falsey
end
end
end
describe "#upload" do
it "delegates to resource#upload" do
checksums = double('checksums')
expect(resource).to receive(:upload).with(subject, checksums)
subject.upload(checksums)
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/data_bag_item_object_spec.rb 0000644 0000041 0000041 00000005157 13123557300 026311 0 ustar www-data www-data require 'spec_helper'
describe Ridley::DataBagItemObject do
let(:resource) { double('chef-resource') }
let(:data_bag) { double('data-bag') }
subject { described_class.new(resource, data_bag) }
describe "#from_hash" do
context "when JSON has a 'raw_data' field" do
let(:response) do
{
"name" => "data_bag_item_ridley-test_appconfig",
"raw_data" => {
"id" => "appconfig",
"host" => "host.local"
},
"json_class" => "Chef::DataBagItem",
"data_bag" => "ridley-test",
"chef_type" => "data_bag_item"
}
end
it "returns a new object from attributes in the 'raw_data' field" do
expect(subject.from_hash(response).attributes).to eql(response["raw_data"])
end
end
context "when JSON does not contain a 'raw_data' field" do
let(:response) do
{
"id" => "appconfig",
"host" => "host.local"
}
end
it "returns a new object from the hash" do
expect(subject.from_hash(response).attributes).to eql(response)
end
end
end
describe "#decrypt" do
before(:each) do
allow(resource).to receive_messages(encrypted_data_bag_secret: File.read(fixtures_path.join("encrypted_data_bag_secret").to_s))
end
it "decrypts an encrypted v0 value" do
subject.attributes[:test] = "Xk0E8lV9r4BhZzcg4wal0X4w9ZexN3azxMjZ9r1MCZc="
subject.decrypt
expect(subject.attributes[:test][:database][:username]).to eq("test")
end
it "decrypts an encrypted v1 value" do
subject.attributes[:password] = Hashie::Mash.new
subject.attributes[:password][:version] = 1
subject.attributes[:password][:cipher] = "aes-256-cbc"
subject.attributes[:password][:encrypted_data] = "zG+tTjtwOWA4vEYDoUwPYreXLZ1pFyKoWDGezEejmKs="
subject.attributes[:password][:iv] = "URVhHxv/ZrnABJBvl82qsg=="
subject.decrypt
expect(subject.attributes[:password]).to eq("password123")
end
it "does not decrypt the id field" do
id = "dbi_id"
subject.attributes[:id] = id
subject.decrypt
expect(subject.attributes[:id]).to eq(id)
end
end
describe "#decrypt_value" do
context "when no encrypted_data_bag_secret has been configured" do
before do
allow(resource).to receive_messages(encrypted_data_bag_secret: nil)
end
it "raises an EncryptedDataBagSecretNotSet error" do
expect {
subject.decrypt_value("Xk0E8lV9r4BhZzcg4wal0X4w9ZexN3azxMjZ9r1MCZc=")
}.to raise_error(Ridley::Errors::EncryptedDataBagSecretNotSet)
end
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/cookbook_object_spec.rb 0000644 0000041 0000041 00000006210 13123557300 025346 0 ustar www-data www-data require 'spec_helper'
describe Ridley::CookbookObject do
let(:connection) { double('connection') }
let(:resource) { double('resource', connection: connection) }
subject { described_class.new(resource) }
describe "#download" do
it "downloads each file" do
allow(subject).to receive(:manifest) do
{
resources: [],
providers: [],
recipes: [
{
checksum: "aa3505d3eb8ce328ea84a4333df05b07",
name: "default.rb",
path: "recipes/default.rb",
specificity: "default",
url: "https://chef.lax1.riotgames.com/organizations/reset/cookbooks/ohai/1.0.2/files/aa3505d3eb8ce328ea84a4333df05b07"
}
],
definitions: [],
libraries: [],
attributes: [],
files: [
{
checksum: "85bc3bb921efade3f2566a668ab4b639",
name: "README",
path: "files/default/plugins/README",
specificity: "plugins",
url: "https://chef.lax1.riotgames.com/organizations/reset/cookbooks/ohai/1.0.2/files/85bc3bb921efade3f2566a668ab4b639"
}
],
templates: [],
root_files: []
}
end
expect(subject).to receive(:download_file).with(:recipes, "recipes/default.rb", anything)
expect(subject).to receive(:download_file).with(:files, "files/default/plugins/README", anything)
subject.download
end
end
describe "#download_file" do
let(:destination) { tmp_path.join('fake.file').to_s }
before(:each) do
allow(subject).to receive(:root_files) { [ { path: 'metadata.rb', url: "http://test.it/file" } ] }
end
it "downloads the file from the file's url" do
expect(connection).to receive(:stream).with("http://test.it/file", destination)
subject.download_file(:root_file, "metadata.rb", destination)
end
context "when given an unknown filetype" do
it "raises an UnknownCookbookFileType error" do
expect {
subject.download_file(:not_existant, "default.rb", destination)
}.to raise_error(Ridley::Errors::UnknownCookbookFileType)
end
end
context "when the cookbook doesn't have the specified file" do
before(:each) do
allow(subject).to receive(:root_files) { Array.new }
end
it "returns nil" do
expect(subject.download_file(:root_file, "metadata.rb", destination)).to be_nil
end
end
end
describe "#manifest" do
it "returns a Hash" do
expect(subject.manifest).to be_a(Hash)
end
it "has a key for each item in FILE_TYPES" do
expect(subject.manifest.keys).to match_array(described_class::FILE_TYPES)
end
it "contains an empty array for each key" do
expect(subject.manifest).to each be_a(Array)
expect(subject.manifest.values).to each be_empty
end
end
describe "#reload" do
it "returns the updated self" do
other = subject.dup
other.version = "1.2.3"
expect(resource).to receive(:find).with(subject, subject.version).and_return(other)
expect(subject.reload).to eq(other)
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_objects/role_object_spec.rb 0000644 0000041 0000041 00000003465 13123557300 024512 0 ustar www-data www-data require 'spec_helper'
describe Ridley::RoleObject do
subject { described_class.new(double('registry')) }
describe "#set_override_attribute" do
it "sets an override node attribute at the nested path" do
subject.set_override_attribute('deep.nested.item', true)
expect(subject.override_attributes).to have_key("deep")
expect(subject.override_attributes["deep"]).to have_key("nested")
expect(subject.override_attributes["deep"]["nested"]).to have_key("item")
expect(subject.override_attributes["deep"]["nested"]["item"]).to be_truthy
end
context "when the override attribute is already set" do
it "test" do
subject.override_attributes = {
deep: {
nested: {
item: false
}
}
}
subject.set_override_attribute('deep.nested.item', true)
expect(subject.override_attributes["deep"]["nested"]["item"]).to be_truthy
end
end
end
describe "#set_default_attribute" do
it "sets an override node attribute at the nested path" do
subject.set_default_attribute('deep.nested.item', true)
expect(subject.default_attributes).to have_key("deep")
expect(subject.default_attributes["deep"]).to have_key("nested")
expect(subject.default_attributes["deep"]["nested"]).to have_key("item")
expect(subject.default_attributes["deep"]["nested"]["item"]).to be_truthy
end
context "when the override attribute is already set" do
it "test" do
subject.default_attributes = {
deep: {
nested: {
item: false
}
}
}
subject.set_default_attribute('deep.nested.item', true)
expect(subject.default_attributes["deep"]["nested"]["item"]).to be_truthy
end
end
end
end
ridley-5.1.1/spec/unit/ridley/connection_spec.rb 0000644 0000041 0000041 00000005653 13123557300 021745 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Connection do
let(:server_url) { "https://api.opscode.com" }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join("reset.pem").to_s }
subject do
described_class.new(server_url, client_name, client_key)
end
context " when proxy environment variables are set" do
subject do
described_class.new('http://127.0.0.1:8889', client_name, client_key)
end
it "fails with http_proxy set without no_proxy" do
stub_const('ENV', ENV.to_hash.merge(
'http_proxy' => 'http://i.am.an.http.proxy')
)
expect { subject.get('/nodes') }.to raise_error(SocketError)
end
it "works with http_proxy and no_proxy set" do
stub_const('ENV', ENV.to_hash.merge(
'http_proxy' => 'http://i.am.an.http.proxy',
'no_proxy' => '127.0.0.1:8889')
)
expect(subject.get('/nodes').status).to eq(200)
end
end
describe "configurable retries" do
before(:each) do
stub_request(:get, "https://api.opscode.com/organizations/vialstudios").to_return(status: 500, body: "")
end
it "attempts five (5) retries by default" do
expect {
subject.get('organizations/vialstudios')
}.to raise_error(Ridley::Errors::HTTPInternalServerError)
expect(a_request(:get, "https://api.opscode.com/organizations/vialstudios")).to have_been_made.times(6)
end
context "given a configured count of two (2) retries" do
subject do
described_class.new(server_url, client_name, client_key, retries: 2)
end
it "attempts two (2) retries" do
expect {
subject.get('organizations/vialstudios')
}.to raise_error(Ridley::Errors::HTTPInternalServerError)
expect(a_request(:get, "https://api.opscode.com/organizations/vialstudios")).to have_been_made.times(3)
end
end
end
describe "#api_type" do
it "returns :foss if the organization is not set" do
subject.stub(:organization).and_return(nil)
expect(subject.api_type).to eql(:foss)
end
it "returns :hosted if the organization is set" do
subject.stub(:organization).and_return("vialstudios")
expect(subject.api_type).to eql(:hosted)
end
end
describe "#stream" do
let(:target) { "http://test.it/file" }
let(:destination) { tmp_path.join("test.file") }
let(:contents) { "SOME STRING STUFF\nHERE.\n" }
before(:each) do
stub_request(:get, "http://test.it/file").to_return(status: 200, body: contents)
end
it "creates a destination file on disk" do
subject.stream(target, destination)
expect(File.exist?(destination)).to be_truthy
end
it "returns true when the file was copied" do
expect(subject.stream(target, destination)).to be_truthy
end
it "contains the contents of the response body" do
subject.stream(target, destination)
expect(File.read(destination)).to include(contents)
end
end
end
ridley-5.1.1/spec/unit/ridley/resources/ 0000755 0000041 0000041 00000000000 13123557300 020250 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/resources/client_resource_spec.rb 0000644 0000041 0000041 00000001727 13123557300 025003 0 ustar www-data www-data require 'spec_helper'
describe Ridley::ClientResource do
subject { described_class.new(double('registry')) }
describe "#regenerate_key" do
let(:client_id) { "rspec-client" }
before { subject.stub(find: nil) }
context "when a client with the given ID exists" do
let(:client) { double('chef-client') }
before { subject.should_receive(:find).with(client_id).and_return(client) }
it "sets the private key to true and updates the client" do
client.should_receive(:private_key=).with(true)
subject.should_receive(:update).with(client)
subject.regenerate_key(client_id)
end
end
context "when a client with the given ID does not exist" do
before { subject.should_receive(:find).with(client_id).and_return(nil) }
it "raises a ResourceNotFound error" do
expect {
subject.regenerate_key(client_id)
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
end
end
ridley-5.1.1/spec/unit/ridley/resources/environment_resource_spec.rb 0000644 0000041 0000041 00000004067 13123557300 026071 0 ustar www-data www-data require 'spec_helper'
describe Ridley::EnvironmentResource do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley::Connection.new(server_url, client_name, client_key) }
let(:resource) do
resource = described_class.new(double('registry'))
resource.stub(connection: connection)
resource
end
subject { resource }
describe "#cookbook_versions" do
let(:name) { "rspec-test" }
let(:run_list) { ["hello", "there"] }
subject { resource.cookbook_versions(name, run_list) }
context "when the chef server has the given cookbooks" do
before do
chef_environment("rspec-test")
chef_cookbook("hello", "1.2.3")
chef_cookbook("there", "1.0.0")
end
it "returns a Hash" do
is_expected.to be_a(Hash)
end
it "contains a key for each cookbook" do
expect(subject.keys.size).to eq(2)
expect(subject).to have_key("hello")
expect(subject).to have_key("there")
end
end
context "when the chef server does not have the environment" do
before do
chef_cookbook("hello", "1.2.3")
chef_cookbook("there", "1.0.0")
end
it "raises a ResourceNotFound error" do
expect { subject }.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
context "when the chef server does not have one or more of the cookbooks" do
it "raises a precondition failed error" do
expect { subject }.to raise_error(Ridley::Errors::HTTPPreconditionFailed)
end
end
end
describe "#delete_all" do
let(:default_env) { double(name: "_default") }
let(:destroy_env) { double(name: "destroy_me") }
before do
subject.stub(all: [ default_env, destroy_env ])
end
it "does not destroy the '_default' environment" do
subject.stub(future: double('future', value: nil))
subject.should_not_receive(:future).with(:delete, default_env)
subject.delete_all
end
end
end
ridley-5.1.1/spec/unit/ridley/resources/search_resource_spec.rb 0000644 0000041 0000041 00000023214 13123557300 024765 0 ustar www-data www-data require 'spec_helper'
describe Ridley::SearchResource do
describe "ClassMethods" do
subject { described_class }
describe "::build_query" do
let(:query_string) { "*:*" }
let(:options) { Hash.new }
it "contains a 'q' key/value" do
result = subject.build_query(query_string, options)
expect(result).to have_key(:q)
expect(result[:q]).to eql(query_string)
end
context "when :sort option is set" do
before { options[:sort] = "DESC" }
it "contains a 'sort' key/value" do
result = subject.build_query(query_string, options)
expect(result).to have_key(:sort)
expect(result[:sort]).to eql("DESC")
end
end
context "when :start option is set" do
before { options[:start] = 1 }
it "contains a 'start' key/value" do
result = subject.build_query(query_string, options)
expect(result).to have_key(:start)
expect(result[:start]).to eql(1)
end
end
context "when :rows option is set" do
before { options[:rows] = 1 }
it "contains a 'rows' key/value" do
result = subject.build_query(query_string, options)
expect(result).to have_key(:rows)
expect(result[:rows]).to eql(1)
end
end
end
describe "::build_param_string" do
let(:query) { "*:*" }
let(:options) { Hash.new }
subject { described_class.build_param_string(query, options) }
it "returns a string containing the query string" do
expect(subject).to eq("?q=#{query}")
end
context "when the :start option is given" do
let(:start) { 10 }
let(:options) { { start: start } }
it "contains the start query param" do
expect(subject).to eq("?q=#{query}&start=#{start}")
end
end
context "when the :sort option is given" do
let(:sort) { "DESC" }
let(:options) { { sort: sort } }
it "contains the sort query param" do
expect(subject).to eq("?q=#{query}&sort=#{sort}")
end
end
context "when the :rows option is given" do
let(:rows) { 20 }
let(:options) { { rows: rows } }
it "contains the rows query param" do
expect(subject).to eq("?q=#{query}&rows=#{rows}")
end
end
end
describe "::query_uri" do
it "returns a URI path containing the search resource path and index" do
expect(subject.query_uri(:nodes)).to eql("search/nodes")
end
end
end
let(:connection) { double('chef-connection') }
subject { described_class.new(double('registry')) }
before { subject.stub(connection: connection) }
describe "#indexes" do
let(:response) do
double(body: {
node: "http://localhost:4000/search/node",
role: "http://localhost:4000/search/role",
client: "http://localhost:4000/search/client",
users: "http://localhost:4000/search/users"
})
end
before do
connection.stub(:get).with(described_class.resource_path).and_return(response)
end
it "performs a GET to the search resource_path" do
connection.should_receive(:get).with(described_class.resource_path).and_return(response)
subject.indexes
end
it "contains a key for each index" do
expect(subject.indexes.size).to eq(4)
end
end
describe "#run" do
let(:index) { :role }
let(:query_string) { "*:*" }
let(:options) { Hash.new }
let(:response) do
double(body: {
rows: Array.new,
total: 0,
start: 0
})
end
let(:registry) { double("registry", :[] => nil) }
let(:run) { subject.run(index, query_string, registry) }
before do
connection.stub(:get).and_return(response)
end
it "builds a query and runs it against the index's resource path" do
query = double('query')
query_uri = double('query-uri')
described_class.should_receive(:build_query).with(query_string, options).and_return(query)
described_class.should_receive(:query_uri).with(index).and_return(query_uri)
connection.should_receive(:get).with(query_uri, query).and_return(response)
subject.run(index, query_string, options)
end
context "when :node is the given index" do
let(:index) { :node }
let(:response) do
double(body: {
rows: [
{
chef_type: "node",
json_class: "Chef::Node",
name: "ridley-one",
chef_environment: "_default",
automatic: {},
normal: {},
default: {},
override: {},
run_list: [
"recipe[one]",
"recipe[two]"
]
}
],
total: 1,
start: 0
})
end
it "returns an array of Ridley::NodeObject" do
result = run
expect(result).to be_a(Array)
expect(result).to each be_a(Ridley::NodeObject)
end
context "after the search has executed and results are returned" do
let(:search_results) { subject.run(index, query_string, registry) }
it "Ridley::NodeObject instances contain the results" do
first_result = search_results.first
expect(first_result.name).to eq("ridley-one")
end
end
end
context "when :role is the given index" do
let(:index) { :role }
let(:response) do
double(body: {
rows: [
{
chef_type: "role",
json_class: "Chef::Role",
name: "ridley-role-one",
description: "",
default_attributes: {},
override_attributes: {},
run_list: [],
env_run_lists: {}
}
],
total: 1,
start: 0
})
end
it "returns an array of Ridley::RoleObject" do
result = run
expect(result).to be_a(Array)
expect(result).to each be_a(Ridley::RoleObject)
end
context "after the search has executed and results are returned" do
let(:search_results) { subject.run(index, query_string, registry) }
it "Ridley::RoleObject instances contain the results" do
first_result = search_results.first
expect(first_result.name).to eq("ridley-role-one")
end
end
end
context "when :environment is the given index" do
let(:index) { :environment }
let(:response) do
double(body: {
rows: [
{
chef_type: "environment",
json_class: "Chef::Environment",
name: "ridley-env-test",
description: "ridley testing environment",
default_attributes: {},
override_attributes: {},
cookbook_versions: {}
}
],
total: 1,
start: 0
})
end
it "returns an array of Ridley::EnvironmentObject" do
result = run
expect(result).to be_a(Array)
expect(result).to each be_a(Ridley::EnvironmentObject)
end
context "after the search has executed and results are returned" do
let(:search_results) { subject.run(index, query_string, registry) }
it "Ridley::EnvironmentObject instances contain the results" do
first_result = search_results.first
expect(first_result.name).to eq("ridley-env-test")
end
end
end
context "when :client is the given index" do
let(:index) { :client }
let(:response) do
double(body: {
rows: [
{
chef_type: "client",
name: "ridley-client-test",
admin: false,
validator: false,
certificate: "-----BEGIN CERTIFICATE-----\nMIIDOjCCAqOgAwIBAgIE47eOmDANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNV\nBAoMDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2Ux\nMjAwBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUu\nY29tMCAXDTEyMTAwOTAwMTUxNVoYDzIxMDExMTA0MDAxNTE1WjCBnTEQMA4GA1UE\nBxMHU2VhdHRsZTETMBEGA1UECBMKV2FzaGluZ3RvbjELMAkGA1UEBhMCVVMxHDAa\nBgNVBAsTE0NlcnRpZmljYXRlIFNlcnZpY2UxFjAUBgNVBAoTDU9wc2NvZGUsIElu\nYy4xMTAvBgNVBAMUKFVSSTpodHRwOi8vb3BzY29kZS5jb20vR1VJRFMvY2xpZW50\nX2d1aWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqB9KEGzl7Wcm/\nwz/x8HByZANCn6WQC+R12qQso5I6nLbTNkRP668jXG3j0R5/F5i/KearAB9ePzL/\nQe3iHtwW6u1qLI1hVNFNB+I1fGu1p6fZyIOjnLn3bqsbOkBplHOIqHsp4GVSsHKb\nD32UXZDa9S9ZFXnR4iT6hUGm5895ReZG9TDiHvBpi9NJFDZXz+AQ6JuQY8UgYMMA\nm80KbO8/NJlXbRW+siRuvr+LIsi9Mx4i63pBWAN46my291rQU31PF3IB+btfGtR/\nyDWDgMSB37bTzZeOf1Dg9fpl2vIXyu3PoHER0oYmrMQbrdwAt7qCHZNuNWn51WPb\n1PHxXL1rAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAGnJUVAv951fUhGyPOrl+LbQG\nqgchMwIn7oDLE863e66BYTDj7koK3jjhx3EBkrT2vt/xS4yW0ZRV1BNqfnNKWbBq\nMNQiKkYdTr+oq2O3plOg/q/M1eG1B5pxGXqvH0O76DVWQcV/svO+HQEi1n8y5UQd\n+pBJCygpuv78wPCM+c4=\n-----END CERTIFICATE-----\n",
public_key: nil,
private_key: nil,
orgname: "ridley"
}
],
total: 1,
start: 0
})
end
it "returns an array of Ridley::ClientObject" do
result = run
expect(result).to be_a(Array)
expect(result).to each be_a(Ridley::ClientObject)
end
context "after the search has executed and results are returned" do
let(:search_results) { subject.run(index, query_string, registry) }
it "Ridley::ClientObject instances contain the results" do
first_result = search_results.first
expect(first_result.name).to eq("ridley-client-test")
end
end
end
end
end
ridley-5.1.1/spec/unit/ridley/resources/user_resource_spec.rb 0000644 0000041 0000041 00000001752 13123557300 024501 0 ustar www-data www-data require 'spec_helper'
describe Ridley::UserResource, type: 'wip' do
subject { described_class.new(double('registry')) }
let(:user_id) { "rspec-user" }
let(:user_password) { "swordfish" }
describe "#regenerate_key" do
before { subject.stub(find: nil) }
context "when a user with the given ID exists" do
let(:user) { double('chef-user') }
before { subject.should_receive(:find).with(user_id).and_return(user) }
it "sets the private key to true and updates the user" do
user.should_receive(:private_key=).with(true)
subject.should_receive(:update).with(user)
subject.regenerate_key(user_id)
end
end
context "when a user with the given ID does not exist" do
before { subject.should_receive(:find).with(user_id).and_return(nil) }
it "raises a ResourceNotFound error" do
expect {
subject.regenerate_key(user_id)
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
end
end
ridley-5.1.1/spec/unit/ridley/resources/data_bag_item_resource_spec.rb 0000644 0000041 0000041 00000000165 13123557300 026260 0 ustar www-data www-data require 'spec_helper'
describe Ridley::DataBagItemResource do
subject { described_class.new(double) }
skip
end
ridley-5.1.1/spec/unit/ridley/resources/cookbook_resource_spec.rb 0000644 0000041 0000041 00000010716 13123557300 025331 0 ustar www-data www-data require 'spec_helper'
describe Ridley::CookbookResource do
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem') }
let(:connection) { Ridley::Connection.new("http://localhost:8889", "reset", fixtures_path.join("reset.pem").to_s) }
subject { described_class.new(double('registry'), client_name, client_key) }
before { subject.stub(connection: connection) }
describe "#download" do
let(:name) { "example_cookbook" }
let(:version) { "0.1.0" }
let(:destination) { tmp_path.join("example_cookbook-0.1.0").to_s }
context "when the cookbook of the name/version is not found" do
before { subject.should_receive(:find).with(name, version).and_return(nil) }
it "raises a ResourceNotFound error" do
expect {
subject.download(name, version, destination)
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
end
describe "#latest_version" do
let(:name) { "ant" }
context "when the cookbook has no versions" do
it "returns a ResourceNotFound error" do
expect {
subject.latest_version(name)
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
context "when the cookbook has versions" do
before do
chef_cookbook(name, "1.0.0")
chef_cookbook(name, "1.2.0")
chef_cookbook(name, "3.0.0")
end
it "returns the latest version" do
expect(subject.latest_version(name)).to eql("3.0.0")
end
end
end
describe "#versions" do
let(:name) { "artifact" }
context "when the cookbook has versions" do
before do
chef_cookbook(name, "1.0.0")
chef_cookbook(name, "1.1.0")
chef_cookbook(name, "1.2.0")
end
it "returns an array" do
expect(subject.versions(name)).to be_a(Array)
end
it "contains a version string for each cookbook version available" do
result = subject.versions(name)
expect(result.size).to eq(3)
expect(result).to include("1.0.0")
expect(result).to include("1.1.0")
expect(result).to include("1.2.0")
end
end
context "when the cookbook has no versions" do
it "raises a ResourceNotFound error" do
expect {
subject.versions(name)
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
end
describe "#satisfy" do
let(:name) { "ridley_test" }
context "when there is a solution" do
before do
chef_cookbook(name, "2.0.0")
chef_cookbook(name, "3.0.0")
end
it "returns a CookbookObject" do
expect(subject.satisfy(name, ">= 2.0.0")).to be_a(Ridley::CookbookObject)
end
it "is the best solution" do
expect(subject.satisfy(name, ">= 2.0.0").version).to eql("3.0.0")
end
end
context "when there is no solution" do
before { chef_cookbook(name, "1.0.0") }
it "returns nil" do
expect(subject.satisfy(name, ">= 2.0.0")).to be_nil
end
end
context "when the cookbook does not exist" do
it "raises a ResourceNotFound error" do
expect {
subject.satisfy(name, ">= 1.2.3")
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
end
describe "#upload" do
let(:name) { "upload_test" }
let(:cookbook_path) { fixtures_path.join('example_cookbook') }
let(:sandbox_resource) { double('sandbox_resource') }
let(:sandbox) { double('sandbox', upload: nil, commit: nil) }
before do
subject.stub(:sandbox_resource).and_return(sandbox_resource)
end
it 'does not include files that are ignored' do
# These are the MD5s for the files. It's not possible to check that
# the ignored files weren't uploaded, so we just check that the
# non-ignored files are the ONLY thing uploaded
sandbox_resource.should_receive(:create).with([
"211a3a8798d4acd424af15ff8a2e28a5",
"5f025b0817442ec087c4e0172a6d1e67",
"75077ba33d2887cc1746d1ef716bf8b7",
"7b1ebd2ff580ca9dc46fb27ec1653bf2",
"84e12365e6f4ebe7db6a0e6a92473b16",
"a39eb80def9804f4b118099697cc2cd2",
"b70ba735f3af47e5d6fc71b91775b34c",
"cafb6869fca13f5c36f24a60de8fb982",
"dbf3a6c4ab68a86172be748aced9f46e",
"dc6461b5da25775f3ef6a9cc1f6cff9f",
"e9a2e24281cfbd6be0a6b1af3b6d277e"
]).and_return(sandbox)
subject.upload(cookbook_path, validate: false)
end
end
describe "#update" do
skip
end
end
ridley-5.1.1/spec/unit/ridley/resources/node_resource_spec.rb 0000644 0000041 0000041 00000002623 13123557300 024446 0 ustar www-data www-data require 'spec_helper'
describe Ridley::NodeResource do
let(:instance) do
inst = described_class.new(double)
inst.stub(connection: chef_zero_connection)
inst
end
describe "#merge_data" do
let(:node_name) { "rspec-test" }
let(:run_list) { [ "recipe[one]", "recipe[two]" ] }
let(:attributes) { { deep: { two: "val" } } }
subject(:result) { instance.merge_data(node_name, run_list: run_list, attributes: attributes) }
context "when a node of the given name exists" do
before do
chef_node(node_name,
run_list: [ "recipe[one]", "recipe[three]" ],
normal: { deep: { one: "val" } }
)
end
it "returns a Ridley::NodeObject" do
expect(result).to be_a(Ridley::NodeObject)
end
it "has a union between the run list of the original node and the new run list" do
expect(result.run_list).to eql(["recipe[one]","recipe[three]","recipe[two]"])
end
it "has a deep merge between the attributes of the original node and the new attributes" do
expect(result.normal.to_hash).to eql("deep" => { "one" => "val", "two" => "val" })
end
end
context "when a node with the given name does not exist" do
let(:node_name) { "does_not_exist" }
it "raises a ResourceNotFound error" do
expect { result }.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
end
end
ridley-5.1.1/spec/unit/ridley/resources/role_resource_spec.rb 0000644 0000041 0000041 00000000156 13123557300 024461 0 ustar www-data www-data require 'spec_helper'
describe Ridley::RoleResource do
subject { described_class.new(double) }
skip
end
ridley-5.1.1/spec/unit/ridley/resources/data_bag_resource_spec.rb 0000644 0000041 0000041 00000001017 13123557300 025237 0 ustar www-data www-data require 'spec_helper'
describe Ridley::DataBagResource do
let(:secret) { "supersecretkey" }
let(:instance) { described_class.new(double, secret) }
describe "#item_resource" do
subject { instance.item_resource }
it "returns a DataBagItemResource" do
expect(subject).to be_a(Ridley::DataBagItemResource)
end
describe '#encrypted_data_bag_secret' do
subject { super().encrypted_data_bag_secret }
it { is_expected.to eql(secret) }
end
end
describe "#find" do
skip
end
end
ridley-5.1.1/spec/unit/ridley/resources/sandbox_resource_spec.rb 0000644 0000041 0000041 00000012015 13123557300 025153 0 ustar www-data www-data require 'spec_helper'
describe Ridley::SandboxResource do
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem') }
let(:connection) { double('chef-connection') }
subject { described_class.new(double, client_name, client_key) }
before { subject.stub(connection: connection) }
describe "#create" do
let(:sandbox_id) { "bd091b150b0a4578b97771af6abf3e05" }
let(:sandbox_uri) { "https://api.opscode.com/organizations/vialstudios/sandboxes/bd091b150b0a4578b97771af6abf3e05" }
let(:checksums) { Hash.new }
let(:response) do
double(body: { uri: sandbox_uri, checksums: checksums, sandbox_id: sandbox_id })
end
before(:each) do
connection.stub(:post).
with(subject.class.resource_path, JSON.fast_generate(checksums: checksums)).
and_return(response)
end
it "returns a Ridley::SandboxObject" do
expect(subject.create).to be_a(Ridley::SandboxObject)
end
it "has a value of 'false' for :is_completed" do
expect(subject.create.is_completed).to be_falsey
end
it "has an empty Hash of checksums" do
expect(subject.create.checksums).to be_a(Hash)
expect(subject.create.checksums).to be_empty
end
it "has a value for :uri" do
expect(subject.create.uri).to eql(sandbox_uri)
end
it "has a value for :sandbox_id" do
expect(subject.create.sandbox_id).to eql(sandbox_id)
end
context "when given an array of checksums" do
let(:checksums) do
{
"385ea5490c86570c7de71070bce9384a" => nil,
"f6f73175e979bd90af6184ec277f760c" => nil,
"2e03dd7e5b2e6c8eab1cf41ac61396d5" => nil
}
end
let(:checksum_array) { checksums.keys }
it "has a Hash of checksums with each of the given checksum ids" do
expect(subject.create(checksum_array).checksums.size).to eq(checksum_array.length)
end
end
end
describe "#commit" do
let(:sandbox_id) { "bd091b150b0a4578b97771af6abf3e05" }
let(:sandbox_path) { "#{described_class.resource_path}/#{sandbox_id}" }
let(:response) do
double(body: {
is_completed: true,
_rev: "1-bbc8a96f7486aeba2b562d382142fd68",
create_time: "2013-01-16T01:43:43+00:00",
guid: "bd091b150b0a4578b97771af6abf3e05",
json_class: "Chef::Sandbox",
name: "bd091b150b0a4578b97771af6abf3e05",
checksums: [],
chef_type: "sandbox"
})
end
it "sends a /PUT to the sandbox resource with is_complete set to true" do
connection.should_receive(:put).with(sandbox_path, JSON.fast_generate(is_completed: true)).and_return(response)
subject.commit(sandbox_id)
end
context "when a sandbox of the given ID is not found" do
before do
connection.should_receive(:put).and_raise(Ridley::Errors::HTTPNotFound.new({}))
end
it "raises a ResourceNotFound error" do
expect {
subject.commit(sandbox_id)
}.to raise_error(Ridley::Errors::ResourceNotFound)
end
end
context "when the given sandbox contents are malformed" do
before do
connection.should_receive(:put).and_raise(Ridley::Errors::HTTPBadRequest.new({}))
end
it "raises a SandboxCommitError error" do
expect {
subject.commit(sandbox_id)
}.to raise_error(Ridley::Errors::SandboxCommitError)
end
end
context "when the user who made the request is not authorized" do
it "raises a PermissionDenied error on unauthorized" do
connection.should_receive(:put).and_raise(Ridley::Errors::HTTPUnauthorized.new({}))
expect {
subject.commit(sandbox_id)
}.to raise_error(Ridley::Errors::PermissionDenied)
end
it "raises a PermissionDenied error on forbidden" do
connection.should_receive(:put).and_raise(Ridley::Errors::HTTPForbidden.new({}))
expect {
subject.commit(sandbox_id)
}.to raise_error(Ridley::Errors::PermissionDenied)
end
end
end
describe "#update" do
it "is not a supported action" do
expect {
subject.update(anything)
}.to raise_error(RuntimeError, "action not supported")
end
end
describe "#update" do
it "is not a supported action" do
expect {
subject.update
}.to raise_error(RuntimeError, "action not supported")
end
end
describe "#all" do
it "is not a supported action" do
expect {
subject.all
}.to raise_error(RuntimeError, "action not supported")
end
end
describe "#find" do
it "is not a supported action" do
expect {
subject.find
}.to raise_error(RuntimeError, "action not supported")
end
end
describe "#delete" do
it "is not a supported action" do
expect {
subject.delete
}.to raise_error(RuntimeError, "action not supported")
end
end
describe "#delete_all" do
it "is not a supported action" do
expect {
subject.delete_all
}.to raise_error(RuntimeError, "action not supported")
end
end
end
ridley-5.1.1/spec/unit/ridley/chef_object_spec.rb 0000644 0000041 0000041 00000015147 13123557300 022040 0 ustar www-data www-data describe Ridley::ChefObject do
let(:resource) { double('chef-resource') }
describe "ClassMethods" do
subject { Class.new(described_class) }
describe "::new" do
it "mass assigns the given attributes" do
new_attrs = {
name: "a name"
}
expect_any_instance_of(subject).to receive(:mass_assign).with(new_attrs)
subject.new(resource, new_attrs)
end
end
describe "::set_chef_type" do
it "sets the chef_type attr on the class" do
subject.set_chef_type("environment")
expect(subject.chef_type).to eql("environment")
end
end
describe "::set_chef_json_class" do
it "sets the chef_json_class attr on the class" do
subject.set_chef_json_class("Chef::Environment")
expect(subject.chef_json_class).to eql("Chef::Environment")
end
end
describe "::set_chef_id" do
it "sets the chef_id attribute on the class" do
subject.set_chef_id(:environment)
expect(subject.chef_id).to eql(:environment)
end
end
describe "::chef_type" do
it "returns the underscored name of the including class if nothing is set" do
expect(subject.chef_type).to eql(subject.class.name.underscore)
end
end
describe "::chef_json_class" do
it "returns the chef_json if nothing has been set" do
expect(subject.chef_json_class).to be_nil
end
end
describe "::chef_id" do
it "returns nil if nothing is set" do
expect(subject.chef_id).to be_nil
end
end
end
subject do
Class.new(described_class).new(resource)
end
describe "#save" do
context "when the object is valid" do
before(:each) { allow(subject).to receive(:valid?).and_return(true) }
it "sends a create message to the implementing class" do
updated = double('updated')
allow(updated).to receive(:_attributes_).and_return(Hash.new)
expect(resource).to receive(:create).with(subject).and_return(updated)
subject.save
end
context "when there is an HTTPConflict" do
it "sends the update message to self" do
updated = double('updated')
allow(updated).to receive(:[]).and_return(Hash.new)
allow(updated).to receive(:_attributes_).and_return(Hash.new)
expect(resource).to receive(:create).and_raise(Ridley::Errors::HTTPConflict.new(updated))
expect(subject).to receive(:update).and_return(updated)
subject.save
end
end
end
context "when the object is invalid" do
before(:each) { allow(subject).to receive(:valid?).and_return(false) }
it "raises an InvalidResource error" do
expect {
subject.save
}.to raise_error(Ridley::Errors::InvalidResource)
end
end
end
describe "#update" do
context "when the object is valid" do
let(:updated) do
updated = double('updated')
allow(updated).to receive(:[]).and_return(Hash.new)
allow(updated).to receive(:_attributes_).and_return(Hash.new)
updated
end
before(:each) { allow(subject).to receive(:valid?).and_return(true) }
it "sends an update message to the implementing class" do
expect(resource).to receive(:update).with(subject).and_return(updated)
subject.update
end
it "returns true" do
expect(resource).to receive(:update).with(subject).and_return(updated)
expect(subject.update).to eql(true)
end
end
context "when the object is invalid" do
before(:each) { allow(subject).to receive(:valid?).and_return(false) }
it "raises an InvalidResource error" do
expect {
subject.update
}.to raise_error(Ridley::Errors::InvalidResource)
end
end
end
describe "#chef_id" do
it "returns the value of the chef_id attribute" do
subject.class.attribute(:name)
allow(subject.class).to receive(:chef_id) { :name }
subject.mass_assign(name: "reset")
expect(subject.chef_id).to eql("reset")
end
end
describe "#reload" do
let(:updated_subject) { double('updated_subject', _attributes_: { one: "val" }) }
before(:each) do
subject.class.attribute(:one)
subject.class.attribute(:two)
allow(resource).to receive(:find).with(subject).and_return(updated_subject)
end
it "returns itself" do
expect(subject.reload).to eql(subject)
end
it "sets the attributes of self to equal those of the updated object" do
subject.reload
expect(subject.get_attribute(:one)).to eql("val")
end
it "does not include attributes not set by the updated object" do
subject.two = "other"
subject.reload
expect(subject.two).to be_nil
end
end
describe "comparable" do
subject do
Class.new(described_class) do
set_chef_id "name"
attribute "name"
attribute "other_extra"
attribute "extra"
end
end
let(:one) { subject.new(resource) }
let(:two) { subject.new(resource) }
context "given two objects with the same value for their 'chef_id'" do
before(:each) do
one.mass_assign(name: "reset", other_extra: "stuff")
two.mass_assign(name: "reset", extra: "stuff")
end
it "is equal" do
expect(one).to be_eql(two)
end
end
context "given two objects with different values for their 'chef_id'" do
before(:each) do
one.mass_assign(name: "jamie", other_extra: "stuff")
two.mass_assign(name: "winsor", extra: "stuff")
end
it "is not equal" do
expect(one).not_to be_eql(two)
end
end
end
describe "uniqueness" do
subject do
Class.new(described_class) do
set_chef_id "name"
attribute "name"
attribute "other_extra"
attribute "extra"
end
end
let(:one) { subject.new(resource) }
let(:two) { subject.new(resource) }
context "given an array of objects with the same value for their 'chef_id'" do
let(:nodes) do
one.mass_assign(name: "reset", other_extra: "stuff")
two.mass_assign(name: "reset", extra: "stuff")
[ one, two ]
end
it "returns only one unique element" do
expect(nodes.uniq.size).to eq(1)
end
end
context "given an array of objects with different values for their 'chef_id'" do
let(:nodes) do
one.mass_assign(name: "jamie", other_extra: "stuff")
two.mass_assign(name: "winsor", extra: "stuff")
[ one, two ]
end
it "returns all of the elements" do
expect(nodes.uniq.size).to eq(2)
end
end
end
end
ridley-5.1.1/spec/unit/ridley/errors_spec.rb 0000644 0000041 0000041 00000002355 13123557300 021116 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Errors do
describe Ridley::Errors::HTTPError do
describe "ClassMethods" do
subject { Ridley::Errors::HTTPError }
before(:each) do
@original = Ridley::Errors::HTTPError.class_variable_get :@@error_map
Ridley::Errors::HTTPError.class_variable_set :@@error_map, Hash.new
end
after(:each) do
Ridley::Errors::HTTPError.class_variable_set :@@error_map, @original
end
describe "::register_error" do
it "adds an item to the error map" do
subject.register_error(400)
expect(subject.error_map.size).to eq(1)
end
it "adds a key of the given status code with a value of the class inheriting from HTTPError" do
class RidleyTestHTTPError < Ridley::Errors::HTTPError
register_error(400)
end
expect(subject.error_map[400]).to eql(RidleyTestHTTPError)
end
end
end
context "with an HTML error payload" do
subject { Ridley::Errors::HTTPError.new(:body => "
Redirected
") }
it "has an HTML body" do
expect(subject.message).to eq("
Redirected
")
end
end
end
end
ridley-5.1.1/spec/unit/ridley/chef/ 0000755 0000041 0000041 00000000000 13123557300 017143 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/chef/cookbook/ 0000755 0000041 0000041 00000000000 13123557300 020751 5 ustar www-data www-data ridley-5.1.1/spec/unit/ridley/chef/cookbook/syntax_check_spec.rb 0000644 0000041 0000041 00000010355 13123557300 024777 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Chef::Cookbook::SyntaxCheck do
let(:cookbook_dir) { fixtures_path.join('example_cookbook')}
let(:chefignore) { Ridley::Chef::Chefignore.new(cookbook_dir) }
let(:syntax_check) do
described_class.new(fixtures_path, chefignore)
end
subject { syntax_check }
before(:each) do
allow(subject).to receive(:chefignore) { chefignore }
end
describe "#ruby_files" do
it "lists the rb files in a cookbook" do
expect(subject.ruby_files).to include(cookbook_dir.join("libraries/my_lib.rb").to_s)
end
it "does not list the rb files in a cookbook that are ignored" do
expect(subject.ruby_files).not_to include(cookbook_dir.join("ignores/magic.rb").to_s)
end
end
describe "#untested_ruby_files" do
it "filters out validated rb files" do
valid_ruby_file = cookbook_dir.join("libraries/my_lib.rb").to_s
subject.validated(valid_ruby_file)
expect(subject.untested_ruby_files).not_to include(valid_ruby_file)
end
end
describe "#template_files" do
it "lists the erb files in a cookbook" do
expect(subject.template_files).to include(cookbook_dir.join("templates/default/temp.txt.erb").to_s)
end
it "does not list the erb files in a cookbook that are ignored" do
expect(subject.template_files).not_to include(cookbook_dir.join("ignores/magic.erb").to_s)
end
end
describe "#untested_template_files" do
it "filters out validated erb files" do
valid_template_file = cookbook_dir.join("templates/default/temp.txt.erb").to_s
subject.validated(valid_template_file)
expect(subject.untested_template_files).not_to include(valid_template_file)
end
end
describe "#validated?" do
it "checks if a file has already been validated" do
valid_template_file = cookbook_dir.join("templates/default/temp.txt.erb").to_s
subject.validated(valid_template_file)
expect(subject.validated?(valid_template_file)).to be_truthy
end
end
describe "#validated" do
let(:validated_files) { double('validated_files') }
before(:each) do
allow(subject).to receive(:validated_files) { validated_files }
end
it "records a file as validated" do
template_file = cookbook_dir.join("templates/default/temp.txt.erb").to_s
file_checksum = Ridley::Chef::Digester.checksum_for_file(template_file)
expect(validated_files).to receive(:add).with(file_checksum)
expect(subject.validated(template_file)).to be_nil
end
end
describe "#validate_ruby_files" do
it "asks #untested_ruby_files for a list of files and calls #validate_ruby_file on each" do
allow(subject).to receive(:validate_ruby_file).with(anything()).exactly(9).times { true }
expect(subject.validate_ruby_files).to be_truthy
end
it "marks the successfully validated ruby files" do
allow(subject).to receive(:validated).with(anything()).exactly(9).times
expect(subject.validate_ruby_files).to be_truthy
end
it "returns false if any ruby file fails to validate" do
allow(subject).to receive(:validate_ruby_file).with(/\.rb$/) { false }
expect(subject.validate_ruby_files).to be_falsey
end
end
describe "#validate_templates" do
it "asks #untested_template_files for a list of erb files and calls #validate_template on each" do
allow(subject).to receive(:validate_template).with(anything()).exactly(9).times { true }
expect(subject.validate_templates).to be_truthy
end
it "marks the successfully validated erb files" do
allow(subject).to receive(:validated).with(anything()).exactly(9).times
expect(subject.validate_templates).to be_truthy
end
it "returns false if any erb file fails to validate" do
allow(subject).to receive(:validate_template).with(/\.erb$/) { false }
expect(subject.validate_templates).to be_falsey
end
end
describe "#validate_template" do
it "asks #shell_out to check the files syntax"
end
describe "#validate_ruby_file" do
it "asks #shell_out to check the files syntax"
end
describe "without a chefignore" do
let(:chefignore) { nil }
it "the file listing still works" do
expect(subject.ruby_files).to include(cookbook_dir.join("libraries/my_lib.rb").to_s)
end
end
end
ridley-5.1.1/spec/unit/ridley/chef/cookbook/metadata_spec.rb 0000644 0000041 0000041 00000002206 13123557300 024070 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Chef::Cookbook::Metadata do
let(:metadata) do
described_class.new
end
before(:each) do
subject { metadata }
end
describe "#validate_choice_array" do
it "should limit the types allowed in the choice array." do
options = {
:type => "string",
:choice => [ "test1", "test2" ],
:default => "test1"
}
expect {
subject.attribute("test_cookbook/test", options)
}.not_to raise_error
options = {
:type => "boolean",
:choice => [ true, false ],
:default => true
}
expect {
subject.attribute("test_cookbook/test", options)
}.not_to raise_error
options = {
:type => "numeric",
:choice => [ 1337, 420 ],
:default => 1337
}
expect {
subject.attribute("test_cookbook/test", options)
}.not_to raise_error
options = {
:type => "numeric",
:choice => [ true, "false" ],
:default => false
}
expect {
subject.attribute("test_cookbook/test", options)
}.to raise_error
end
end
end
ridley-5.1.1/spec/unit/ridley/chef/cookbook_spec.rb 0000644 0000041 0000041 00000045307 13123557300 022321 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Chef::Cookbook do
describe "ClassMethods" do
subject { described_class }
describe "::from_path" do
let(:cookbook_path) { fixtures_path.join("example_cookbook") }
it "returns an instance of Ridley::Chef::Cookbook" do
expect(subject.from_path(cookbook_path)).to be_a(described_class)
end
it "has a cookbook_name attribute set to the value of the 'name' attribute in the metadata" do
expect(subject.from_path(cookbook_path).cookbook_name).to eql("example_cookbook")
end
context "given a path that does not contain a metadata file" do
it "raises an IOError" do
expect {
subject.from_path(Dir.mktmpdir)
}.to raise_error(IOError)
end
end
context "when the metadata does not contain a value for name and no value for :name option was given" do
let(:cookbook_path) { tmp_path.join("directory_name").to_s }
before do
FileUtils.mkdir_p(cookbook_path)
FileUtils.touch(File.join(cookbook_path, 'metadata.rb'))
end
it "raises an exception" do
expect {
subject.from_path(cookbook_path)
}.to raise_error(Ridley::Errors::MissingNameAttribute)
end
end
context "when a metadata.json is missing but metadata.rb is present" do
let(:cookbook_path) { tmp_path.join("temp_cookbook").to_s }
before do
FileUtils.mkdir_p(cookbook_path)
File.open(File.join(cookbook_path, 'metadata.rb'), 'w+') do |f|
f.write <<-EOH
name 'rspec_test'
EOH
end
end
it "sets the name of the cookbook from the metadata.rb" do
expect(subject.from_path(cookbook_path).cookbook_name).to eql("rspec_test")
end
end
context "when a metadata.json and metadata.rb are both present" do
let(:cookbook_path) { tmp_path.join("temp_cookbook").to_s }
before do
FileUtils.mkdir_p(cookbook_path)
File.open(File.join(cookbook_path, 'metadata.json'), 'w+') do |f|
f.write JSON.fast_generate(name: "json_metadata")
end
File.open(File.join(cookbook_path, 'metadata.rb'), 'w+') do |f|
f.write <<-EOH
name 'ruby_metadata'
EOH
end
end
it "prefers the metadata.json" do
expect(subject.from_path(cookbook_path).cookbook_name).to eql("json_metadata")
end
end
end
describe "::checksum" do
it "delegates to Ridley::Chef::Digester.md5_checksum_for_file" do
path = fixtures_path.join("example_cookbook", "metadata.rb")
expect(Ridley::Chef::Digester).to receive(:md5_checksum_for_file).with(path)
subject.checksum(path)
end
end
end
let(:cookbook) do
described_class.from_path(fixtures_path.join('example_cookbook'))
end
subject { cookbook }
describe "#checksums" do
it "returns a Hash" do
expect(subject.checksums).to be_a(Hash)
end
it "has a key value for every cookbook file" do
expect(subject.checksums.size).to eq(subject.send(:files).length)
end
end
describe "#compile_metadata" do
let(:cookbook_path) { tmp_path.join("temp_cookbook").to_s }
subject { described_class.from_path(cookbook_path) }
before do
FileUtils.mkdir_p(cookbook_path)
File.open(File.join(cookbook_path, "metadata.rb"), "w+") do |f|
f.write <<-EOH
name "rspec_test"
version "1.2.3"
EOH
end
end
it "compiles the raw metadata.rb into a metadata.json file in the path of the cookbook" do
expect(subject.compiled_metadata?).to be_falsey
subject.compile_metadata
subject.reload
expect(subject.compiled_metadata?).to be_truthy
expect(subject.cookbook_name).to eql("rspec_test")
expect(subject.version).to eql("1.2.3")
end
context "when given an output path to write the metadata to" do
let(:out_path) { tmp_path.join("outpath") }
before { FileUtils.mkdir_p(out_path) }
it "writes the compiled metadata to a metadata.json file at the given out path" do
subject.compile_metadata(out_path)
expect(File.exist?(File.join(out_path, "metadata.json"))).to be_truthy
end
end
end
describe "#compiled_metadata?" do
let(:cookbook_path) { tmp_path.join("temp_cookbook").to_s }
subject { described_class.from_path(cookbook_path) }
before do
FileUtils.mkdir_p(cookbook_path)
FileUtils.touch(File.join(cookbook_path, "metadata.rb"))
end
context "when a metadata.json file is present" do
before do
File.open(File.join(cookbook_path, 'metadata.json'), 'w+') do |f|
f.write JSON.fast_generate(name: "json_metadata")
end
end
describe '#compiled_metadata?' do
subject { super().compiled_metadata? }
it { is_expected.to be_truthy }
end
end
context "when a metadata.json file is not present" do
before do
FileUtils.rm_f(File.join(cookbook_path, 'metadata.json'))
File.open(File.join(cookbook_path, 'metadata.rb'), 'w+') do |f|
f.write "name 'cookbook'"
end
end
describe '#compiled_metadata?' do
subject { super().compiled_metadata? }
it { is_expected.to be_falsey }
end
end
end
describe "#manifest" do
it "returns a Mash with a key for each cookbook file category" do
[
:recipes,
:definitions,
:libraries,
:attributes,
:files,
:templates,
:resources,
:providers,
:root_files
].each do |category|
expect(subject.manifest).to have_key(category)
end
end
end
describe "#validate" do
let(:syntax_checker) { double('syntax_checker') }
before(:each) do
allow(subject).to receive(:syntax_checker) { syntax_checker }
end
it "asks the syntax_checker to validate the ruby and template files of the cookbook" do
expect(syntax_checker).to receive(:validate_ruby_files).and_return(true)
expect(syntax_checker).to receive(:validate_templates).and_return(true)
subject.validate
end
it "raises CookbookSyntaxError if the cookbook contains invalid ruby files" do
expect(syntax_checker).to receive(:validate_ruby_files).and_return(false)
expect {
subject.validate
}.to raise_error(Ridley::Errors::CookbookSyntaxError)
end
it "raises CookbookSyntaxError if the cookbook contains invalid template files" do
expect(syntax_checker).to receive(:validate_ruby_files).and_return(true)
expect(syntax_checker).to receive(:validate_templates).and_return(false)
expect {
subject.validate
}.to raise_error(Ridley::Errors::CookbookSyntaxError)
end
end
describe "#file_metadata" do
let(:file) { subject.path.join("files", "default", "file.h") }
before(:each) { @metadata = subject.file_metadata(:file, file) }
it "has a :path key whose value is a relative path from the CachedCookbook's path" do
expect(@metadata).to have_key(:path)
expect(@metadata[:path]).to be_relative_path
expect(@metadata[:path]).to eql("files/default/file.h")
end
it "has a :name key whose value is the basename of the target file" do
expect(@metadata).to have_key(:name)
expect(@metadata[:name]).to eql("file.h")
end
it "has a :checksum key whose value is the checksum of the target file" do
expect(@metadata).to have_key(:checksum)
expect(@metadata[:checksum]).to eql("7b1ebd2ff580ca9dc46fb27ec1653bf2")
end
it "has a :specificity key" do
expect(@metadata).to have_key(:specificity)
end
context "given a file or template in a 'default' directory" do
let(:file) { subject.path.join("files", "default", "file.h") }
before(:each) { @metadata = subject.file_metadata(:files, file) }
it "has a specificity of 'default'" do
expect(@metadata[:specificity]).to eql("default")
end
end
context "given a file or template in a 'ubuntu' directory" do
let(:file) { subject.path.join("files", "ubuntu", "file.h") }
before(:each) { @metadata = subject.file_metadata(:files, file) }
it "has a specificity of 'ubuntu'" do
expect(@metadata[:specificity]).to eql("ubuntu")
end
end
end
describe "#file_specificity" do
let(:category) { :templates }
let(:relpath) { 'default.rb' }
let(:file) { subject.path.join(category.to_s, relpath) }
before(:each) { @specificity = subject.file_specificity(category, file) }
context "given a recipe file" do
let(:category) { :recipes }
it "has a specificity of 'default'" do
expect(@specificity).to eql("default")
end
end
context "given a template 'default/config.erb'" do
let(:relpath) { 'default/config.erb' }
it "has a specificity of 'default'" do
expect(@specificity).to eql("default")
end
end
context "given a template 'centos/config.erb'" do
let(:relpath) { 'centos/config.erb' }
it "has a specificity of 'centos'" do
expect(@specificity).to eql("centos")
end
end
context "given a template 'config.erb'" do
let(:relpath) { 'config.erb' }
it "has a specificity of 'root_default'" do
expect(@specificity).to eql("root_default")
end
end
end
describe "#to_hash" do
subject { cookbook.to_hash }
it "has a :frozen? flag" do
expect(subject).to have_key(:frozen?)
end
it "has a :recipes key with a value of an Array Hashes" do
expect(subject).to have_key(:recipes)
expect(subject[:recipes]).to be_a(Array)
subject[:recipes].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :recipes Array of Hashes" do
expect(subject[:recipes].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :recipes Array of Hashes" do
expect(subject[:recipes].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :recipes Array of Hashes" do
expect(subject[:recipes].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :recipes Array of Hashes" do
expect(subject[:recipes].first).to have_key(:specificity)
end
it "has a :definitions key with a value of an Array Hashes" do
expect(subject).to have_key(:definitions)
expect(subject[:definitions]).to be_a(Array)
subject[:definitions].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :definitions Array of Hashes" do
expect(subject[:definitions].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :definitions Array of Hashes" do
expect(subject[:definitions].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :definitions Array of Hashes" do
expect(subject[:definitions].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :definitions Array of Hashes" do
expect(subject[:definitions].first).to have_key(:specificity)
end
it "has a :libraries key with a value of an Array Hashes" do
expect(subject).to have_key(:libraries)
expect(subject[:libraries]).to be_a(Array)
subject[:libraries].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :libraries Array of Hashes" do
expect(subject[:libraries].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :libraries Array of Hashes" do
expect(subject[:libraries].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :libraries Array of Hashes" do
expect(subject[:libraries].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :libraries Array of Hashes" do
expect(subject[:libraries].first).to have_key(:specificity)
end
it "has a :attributes key with a value of an Array Hashes" do
expect(subject).to have_key(:attributes)
expect(subject[:attributes]).to be_a(Array)
subject[:attributes].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :attributes Array of Hashes" do
expect(subject[:attributes].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :attributes Array of Hashes" do
expect(subject[:attributes].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :attributes Array of Hashes" do
expect(subject[:attributes].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :attributes Array of Hashes" do
expect(subject[:attributes].first).to have_key(:specificity)
end
it "has a :files key with a value of an Array Hashes" do
expect(subject).to have_key(:files)
expect(subject[:files]).to be_a(Array)
subject[:files].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :files Array of Hashes" do
expect(subject[:files].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :files Array of Hashes" do
expect(subject[:files].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :files Array of Hashes" do
expect(subject[:files].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :files Array of Hashes" do
expect(subject[:files].first).to have_key(:specificity)
end
it "has a :templates key with a value of an Array Hashes" do
expect(subject).to have_key(:templates)
expect(subject[:templates]).to be_a(Array)
subject[:templates].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :templates Array of Hashes" do
expect(subject[:templates].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :templates Array of Hashes" do
expect(subject[:templates].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :templates Array of Hashes" do
expect(subject[:templates].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :templates Array of Hashes" do
expect(subject[:templates].first).to have_key(:specificity)
end
it "has a :resources key with a value of an Array Hashes" do
expect(subject).to have_key(:resources)
expect(subject[:resources]).to be_a(Array)
subject[:resources].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :resources Array of Hashes" do
expect(subject[:resources].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :resources Array of Hashes" do
expect(subject[:resources].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :resources Array of Hashes" do
expect(subject[:resources].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :resources Array of Hashes" do
expect(subject[:resources].first).to have_key(:specificity)
end
it "has a :providers key with a value of an Array Hashes" do
expect(subject).to have_key(:providers)
expect(subject[:providers]).to be_a(Array)
subject[:providers].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :providers Array of Hashes" do
expect(subject[:providers].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :providers Array of Hashes" do
expect(subject[:providers].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :providers Array of Hashes" do
expect(subject[:providers].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :providers Array of Hashes" do
expect(subject[:providers].first).to have_key(:specificity)
end
it "has a :root_files key with a value of an Array Hashes" do
expect(subject).to have_key(:root_files)
expect(subject[:root_files]).to be_a(Array)
subject[:root_files].each do |item|
expect(item).to be_a(Hash)
end
end
it "has a :name key value pair in a Hash of the :root_files Array of Hashes" do
expect(subject[:root_files].first).to have_key(:name)
end
it "has a :path key value pair in a Hash of the :root_files Array of Hashes" do
expect(subject[:root_files].first).to have_key(:path)
end
it "has a :checksum key value pair in a Hash of the :root_files Array of Hashes" do
expect(subject[:root_files].first).to have_key(:checksum)
end
it "has a :specificity key value pair in a Hash of the :root_files Array of Hashes" do
expect(subject[:root_files].first).to have_key(:specificity)
end
it "has a :cookbook_name key with a String value" do
expect(subject).to have_key(:cookbook_name)
expect(subject[:cookbook_name]).to be_a(String)
end
it "has a :metadata key with a Hashie::Mash value" do
expect(subject).to have_key(:metadata)
expect(subject[:metadata]).to be_a(Hashie::Mash)
end
it "has a :version key with a String value" do
expect(subject).to have_key(:version)
expect(subject[:version]).to be_a(String)
end
it "has a :name key with a String value" do
expect(subject).to have_key(:name)
expect(subject[:name]).to be_a(String)
end
it "has a value containing the cookbook name and version separated by a dash for :name" do
name, version = subject[:name].split('-')
expect(name).to eql(cookbook.cookbook_name)
expect(version).to eql(cookbook.version)
end
it "has a :chef_type key with Cookbook::CHEF_TYPE as the value" do
expect(subject).to have_key(:chef_type)
expect(subject[:chef_type]).to eql(Ridley::Chef::Cookbook::CHEF_TYPE)
end
end
describe "#to_json" do
before(:each) do
@json = subject.to_json
end
it "has a 'json_class' key with Cookbook::CHEF_JSON_CLASS as the value" do
expect(@json).to have_json_path('json_class')
expect(parse_json(@json)['json_class']).to eql(Ridley::Chef::Cookbook::CHEF_JSON_CLASS)
end
it "has a 'frozen?' flag" do
expect(@json).to have_json_path('frozen?')
end
end
end
ridley-5.1.1/spec/unit/ridley/chef/digester_spec.rb 0000644 0000041 0000041 00000001413 13123557300 022307 0 ustar www-data www-data # Borrowed and modified from: {https://github.com/opscode/chef/blob/11.4.0/spec/unit/digester_spec.rb}
require 'spec_helper'
describe Ridley::Chef::Digester do
before(:each) do
@cache = described_class.instance
end
describe "when computing checksums of cookbook files and templates" do
it "proxies the class method checksum_for_file to the instance" do
expect(@cache).to receive(:checksum_for_file).with("a_file_or_a_fail")
described_class.checksum_for_file("a_file_or_a_fail")
end
it "generates a checksum from a non-file IO object" do
io = StringIO.new("riseofthemachines\nriseofthechefs\n")
expected_md5 = '0e157ac1e2dd73191b76067fb6b4bceb'
expect(@cache.generate_md5_checksum(io)).to eq(expected_md5)
end
end
end
ridley-5.1.1/spec/unit/ridley/chef/chefignore_spec.rb 0000644 0000041 0000041 00000001602 13123557300 022612 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Chef::Chefignore do
describe '.initialize' do
let(:path) { tmp_path.join('chefignore-test') }
before { FileUtils.mkdir_p(path) }
it 'finds the nearest chefignore' do
target = path.join('chefignore').to_s
FileUtils.touch(target)
expect(described_class.new(path).filepath).to eq(target)
end
it 'finds a chefignore in the `cookbooks` directory' do
target = path.join('cookbooks', 'chefignore').to_s
FileUtils.mkdir_p(path.join('cookbooks'))
FileUtils.touch(target)
expect(described_class.new(path).filepath).to eq(target)
end
it 'finds a chefignore in the `.chef` directory' do
target = path.join('.chef', 'chefignore').to_s
FileUtils.mkdir_p(path.join('.chef'))
FileUtils.touch(target)
expect(described_class.new(path).filepath).to eq(target)
end
end
end
ridley-5.1.1/spec/unit/ridley/client_spec.rb 0000644 0000041 0000041 00000013422 13123557300 021055 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Client do
let(:server_url) { "https://api.opscode.com" }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join("reset.pem").to_s }
let(:organization) { "vialstudios" }
let(:encrypted_data_bag_secret_path) { fixtures_path.join("reset.pem").to_s }
let(:chef_version) { "10.24.0-01" }
let(:config) do
{
server_url: server_url,
client_name: client_name,
client_key: client_key,
organization: organization,
encrypted_data_bag_secret_path: encrypted_data_bag_secret_path,
chef_version: chef_version
}
end
describe "ClassMethods" do
let(:options) do
{
server_url: "https://api.opscode.com/some_path",
client_name: client_name,
client_key: client_key
}
end
describe "::initialize" do
subject { described_class.new(options) }
describe "parsing the 'server_url' option" do
describe '#host' do
subject { super().host }
it { is_expected.to eql("api.opscode.com") }
end
describe '#scheme' do
subject { super().scheme }
it { is_expected.to eql("https") }
end
describe '#path_prefix' do
subject { super().path_prefix }
it { is_expected.to eql("/") }
end
end
describe "with a server_url containing an organization" do
before do
options[:server_url] = "#{server_url}/organizations/#{organization}"
end
it "gets the host data from the server_url" do
expect(subject.host).to eql("api.opscode.com")
expect(subject.scheme).to eql("https")
end
it "takes the organization out of the server_url and assigns it to the organization reader" do
expect(subject.organization).to eql(organization)
end
it "sets the 'path_prefix' of the connection the organization sub URI" do
expect(subject.path_prefix).to eql("/organizations/#{organization}")
end
end
it "raises 'ArgumentError' if a value for server_url is not given" do
expect {
described_class.new(
client_name: client_name,
client_key: client_key
)
}.to raise_error(ArgumentError, "Missing required option(s): 'server_url'")
end
it "raises if a value for client_name is not given" do
expect {
described_class.new(
server_url: server_url,
client_key: client_key
)
}.to raise_error(ArgumentError, "Missing required option(s): 'client_name'")
end
it "raises if a value for client_key is not given" do
expect {
described_class.new(
server_url: server_url,
client_name: client_name
)
}.to raise_error(ArgumentError, "Missing required option(s): 'client_key'")
end
it "raises a ClientKeyFileNotFound if the client_key is not found or an invalid key" do
config[:client_key] = "/tmp/nofile.xxsa"
expect {
described_class.new(config)
}.to raise_error(Ridley::Errors::ClientKeyFileNotFoundOrInvalid)
end
it "expands the path of the client_key" do
config[:client_key] = "spec/fixtures/reset.pem"
expect(described_class.new(config).client_key[0..4]).not_to eq("spec/")
end
it "accepts a client key as a string" do
key = File.read(fixtures_path.join("reset.pem").to_s)
config[:client_key] = key.dup
expect(described_class.new(config).client_key).to eq(key)
end
it "assigns a 'chef_version' attribute from the given 'chef_version' option" do
expect(described_class.new(config).chef_version).to eql("10.24.0-01")
end
end
describe "::open" do
it "instantiates a new connection, yields to it, and terminates it" do
new_instance = double(alive?: true)
expect(described_class).to receive(:new).and_return(new_instance)
expect(new_instance).to receive(:hello)
expect(new_instance).to receive(:terminate)
described_class.open do |f|
f.hello
end
end
end
end
let(:instance) { described_class.new(config) }
subject { instance }
describe '#client' do
subject { super().client }
it { is_expected.to be_a(Ridley::ClientResource) }
end
describe '#cookbook' do
subject { super().cookbook }
it { is_expected.to be_a(Ridley::CookbookResource) }
end
describe '#data_bag' do
subject { super().data_bag }
it { is_expected.to be_a(Ridley::DataBagResource) }
end
describe '#environment' do
subject { super().environment }
it { is_expected.to be_a(Ridley::EnvironmentResource) }
end
describe '#node' do
subject { super().node }
it { is_expected.to be_a(Ridley::NodeResource) }
end
describe '#role' do
subject { super().role }
it { is_expected.to be_a(Ridley::RoleResource) }
end
describe '#sandbox' do
subject { super().sandbox }
it { is_expected.to be_a(Ridley::SandboxResource) }
end
describe "#encrypted_data_bag_secret" do
subject { instance.encrypted_data_bag_secret }
it { is_expected.to be_a(String) }
context "when a encrypted_data_bag_secret_path is not provided" do
before(:each) do
instance.stub(encrypted_data_bag_secret_path: nil)
end
it "returns nil" do
expect(subject).to be_nil
end
end
context "when the file is not found at the given encrypted_data_bag_secret_path" do
before(:each) do
instance.stub(encrypted_data_bag_secret_path: fixtures_path.join("not.txt").to_s)
end
it "raises an EncryptedDataBagSecretNotFound erorr" do
expect { subject }.to raise_error(Ridley::Errors::EncryptedDataBagSecretNotFound)
end
end
end
end
ridley-5.1.1/spec/unit/ridley/logger_spec.rb 0000644 0000041 0000041 00000003415 13123557300 021057 0 ustar www-data www-data require 'spec_helper'
describe Ridley::Logging::Logger do
subject { described_class.new(File::NULL) }
let(:message) { "my message" }
let(:filtered_param) { "message" }
describe "::initialize" do
it "defaults to info" do
expect(subject.level).to eq(Logger::WARN)
end
end
describe "#info" do
before do
subject.level = Logger::INFO
subject.filter_param filtered_param
end
it "supports filtering" do
expect(subject).to receive(:filter).with("my message").and_return("my FILTERED")
subject.info message
end
end
describe "#filter_params" do
it "returns an array" do
expect(subject.filter_params).to be_a(Array)
end
end
describe "#filter_param" do
let(:param) { "hello" }
before do
subject.clear_filter_params
end
it "adds an element to the array" do
subject.filter_param(param)
expect(subject.filter_params).to include(param)
expect(subject.filter_params.size).to eq(1)
end
context "when the element is already in the array" do
before do
subject.filter_param(param)
end
it "does not duplicate the element" do
subject.filter_param(param)
expect(subject.filter_params.size).to eq(1)
end
end
end
describe "#filter" do
before do
subject.filter_param(filtered_param)
end
it "replaces entries in filter_params" do
expect(subject.filter(message)).to eq("my FILTERED")
end
context "when there are multiple filter_params" do
before do
subject.filter_param("fake param")
subject.filter_param(filtered_param)
end
it "replaces only matching filter_params" do
expect(subject.filter(message)).to eq("my FILTERED")
end
end
end
end
ridley-5.1.1/spec/unit/ridley/sandbox_uploader_spec.rb 0000644 0000041 0000041 00000005746 13123557300 023142 0 ustar www-data www-data require 'spec_helper'
describe Ridley::SandboxUploader do
describe "ClassMethods" do
subject { described_class }
describe "::checksum" do
let(:io) { StringIO.new("some long string") }
subject { described_class.checksum(io) }
it { is_expected.to eq("2fb66bbfb88cdf9e07a3f1d1dfad71ab") }
end
describe "::checksum64" do
let(:io) { StringIO.new("some long string") }
subject { described_class.checksum64(io) }
it { is_expected.to eq("L7Zrv7iM354Ho/HR361xqw==") }
end
end
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem') }
let(:connection) do
double('connection',
client_name: client_name,
client_key: client_key,
options: {}
)
end
let(:resource) { double('resource', connection: connection) }
let(:checksums) do
{
"oGCPHrQ+5MylEL+V+NIJ9w==" => {
needs_upload: true,
url: "https://api.opscode.com/organizations/vialstudios/sandboxes/bd091b150b0a4578b97771af6abf3e05"
}
}
end
let(:sandbox) { Ridley::SandboxObject.new(resource, checksums: checksums) }
subject { described_class.new(client_name, client_key, {}) }
describe "#upload" do
let(:chk_id) { "a0608f1eb43ee4cca510bf95f8d209f7" }
let(:path) { fixtures_path.join('reset.pem').to_s }
let(:different_path) { fixtures_path.join('recipe_one.rb').to_s }
before { connection.stub(foss?: false) }
context "when the checksum needs uploading" do
let(:checksums) do
{
chk_id => {
url: "https://api.opscode.com/organizations/vialstudios/sandboxes/bd091b150b0a4578b97771af6abf3e05",
needs_upload: true
}
}
end
it "uploads each checksum to their target URL" do
stub_request(:put, checksums[chk_id][:url])
subject.upload(sandbox, chk_id, path)
end
it "raises an exception when the calcuated checksum does not match the expected checksum" do
expect { subject.upload(sandbox, chk_id, different_path) }.to raise_error(Ridley::Errors::ChecksumMismatch)
end
end
context "when the checksum doesn't need uploading" do
let(:checksums) do
{
chk_id => {
needs_upload: false
}
}
end
it "returns nil" do
expect(subject.upload(sandbox, chk_id, path)).to be_nil
end
end
context "when the connection is an open source server connection with a non-80 port" do
before do
connection.stub(foss?: true, server_url: "http://localhost:8889")
end
let(:checksums) do
{
chk_id => {
url: "http://localhost/sandboxes/bd091b150b0a4578b97771af6abf3e05",
needs_upload: true
}
}
end
it "does not strip the port from the target to upload to" do
stub_request(:put, "http://localhost:8889/sandboxes/bd091b150b0a4578b97771af6abf3e05")
subject.upload(sandbox, chk_id, path)
end
end
end
end
ridley-5.1.1/spec/support/ 0000755 0000041 0000041 00000000000 13123557300 015503 5 ustar www-data www-data ridley-5.1.1/spec/support/filepath_matchers.rb 0000644 0000041 0000041 00000000635 13123557300 021516 0 ustar www-data www-data require 'pathname'
RSpec::Matchers.define :be_relative_path do
match do |given|
if given.nil?
false
else
Pathname.new(given).relative?
end
end
failure_message do |given|
"Expected '#{given}' to be a relative path but got an absolute path."
end
failure_message_when_negated do |given|
"Expected '#{given}' to not be a relative path but got an absolute path."
end
end
ridley-5.1.1/spec/support/actor_mocking.rb 0000644 0000041 0000041 00000000412 13123557300 020644 0 ustar www-data www-data RSpec.configuration.before(:each) do
class Celluloid::CellProxy
unless @rspec_compatible
@rspec_compatible = true
undef_method :should_receive if method_defined?(:should_receive)
undef_method :stub if method_defined?(:stub)
end
end
end
ridley-5.1.1/spec/support/chef_server.rb 0000644 0000041 0000041 00000003557 13123557300 020335 0 ustar www-data www-data require 'chef_zero/server'
require_relative 'spec_helpers'
module Ridley::RSpec
module ChefServer
class << self
include Ridley::SpecHelpers
def clear_request_log
@request_log = Array.new
end
def request_log
@request_log ||= Array.new
end
def server
@server ||= ChefZero::Server.new(port: PORT, generate_real_keys: false)
end
def server_url
(@server && @server.url) || "http://localhost/#{PORT}"
end
def start
server.start_background
server.on_response do |request, response|
request_log << [ request, response ]
end
clear_request_log
server
end
def stop
@server.stop if @server
end
def running?
@server && @server.running?
end
end
include Ridley::SpecHelpers
PORT = 8889
def chef_client(name, hash = Hash.new)
load_data(:clients, name, hash)
end
def chef_cookbook(name, version, cookbook = Hash.new)
ChefServer.server.load_data("cookbooks" => { "#{name}-#{version}" => cookbook })
end
def chef_data_bag(name, hash = Hash.new)
ChefServer.server.load_data({ 'data' => { name => hash }})
end
def chef_environment(name, hash = Hash.new)
load_data(:environments, name, hash)
end
def chef_node(name, hash = Hash.new)
load_data(:nodes, name, hash)
end
def chef_role(name, hash = Hash.new)
load_data(:roles, name, hash)
end
def chef_user(name, hash = Hash.new)
load_data(:users, name, hash)
end
def chef_zero_connection
Ridley::Connection.new(ChefServer.server_url, "reset", fixtures_path.join('reset.pem').to_s)
end
private
def load_data(key, name, hash)
ChefServer.server.load_data(key.to_s => { name => JSON.fast_generate(hash) })
end
end
end
ridley-5.1.1/spec/support/shared_examples/ 0000755 0000041 0000041 00000000000 13123557300 020647 5 ustar www-data www-data ridley-5.1.1/spec/support/shared_examples/ridley_resource.rb 0000644 0000041 0000041 00000013653 13123557300 024403 0 ustar www-data www-data shared_examples_for "a Ridley Resource" do |resource_klass|
let(:connection) { double('connection', hosted?: true) }
let(:client) { double('client', connection: connection) }
let(:active_connection) { double('active-connection') }
let(:response) { double('response') }
describe "ClassMethods" do
subject { resource_klass }
describe "::all" do
it "sends a get request for the class' resource_path using the given client" do
allow(response).to receive(:body) { Hash.new }
expect(client.connection).to receive(:get).with(subject.resource_path).and_return(response)
subject.all(client)
end
end
describe "::find" do
it "sends a get request to the given client to the resource_path of the class for the given chef_id" do
chef_id = "ridley_test"
allow(response).to receive(:body) { Hash.new }
expect(client.connection).to receive(:get).with("#{subject.resource_path}/#{chef_id}").and_return(response)
subject.find(client, chef_id)
end
end
describe "::create" do
it "sends a post request to the given client using the includer's resource_path" do
attrs = {
first_name: "jamie",
last_name: "winsor"
}
allow(response).to receive(:body) { attrs }
expect(client.connection).to receive(:post).with(subject.resource_path, duck_type(:to_json)).and_return(response)
subject.create(client, attrs)
end
end
describe "::delete" do
it "sends a delete request to the given client using the includer's resource_path for the given string" do
allow(response).to receive(:body) { Hash.new }
expect(client.connection).to receive(:delete).with("#{subject.resource_path}/ridley-test").and_return(response)
subject.delete(client, "ridley-test")
end
it "accepts an object that responds to 'chef_id'" do
object = double("obj")
allow(object).to receive(:chef_id) { "hello" }
allow(response).to receive(:body) { Hash.new }
expect(client.connection).to receive(:delete).with("#{subject.resource_path}/#{object.chef_id}").and_return(response)
subject.delete(client, object)
end
end
describe "::delete_all" do
it "sends a delete request for every object in the collection" do
skip
end
end
describe "::update" do
it "sends a put request to the given client using the includer's resource_path with the given object" do
allow(subject).to receive(:chef_id) { :name }
subject.attribute(:name)
object = subject.new(name: "hello")
allow(response).to receive(:body) { Hash.new }
expect(client.connection).to receive(:put).with("#{subject.resource_path}/#{object.chef_id}", duck_type(:to_json)).and_return(response)
subject.update(client, object)
end
end
end
subject { resource_klass.new(client) }
describe "#save" do
context "when the object is valid" do
before(:each) { allow(subject).to receive(:valid?).and_return(true) }
it "sends a create message to the implementing class" do
updated = double('updated')
allow(updated).to receive(:_attributes_).and_return(Hash.new)
expect(subject.class).to receive(:create).with(client, subject).and_return(updated)
subject.save
end
context "when there is an HTTPConflict" do
it "sends the update message to self" do
updated = double('updated')
allow(updated).to receive(:[]).and_return(Hash.new)
allow(updated).to receive(:_attributes_).and_return(Hash.new)
expect(subject.class).to receive(:create).and_raise(Ridley::Errors::HTTPConflict.new(updated))
expect(subject).to receive(:update).and_return(updated)
subject.save
end
end
end
context "when the object is invalid" do
before(:each) { allow(subject).to receive(:valid?).and_return(false) }
it "raises an InvalidResource error" do
expect {
subject.save
}.to raise_error(Ridley::Errors::InvalidResource)
end
end
end
describe "#update" do
context "when the object is valid" do
let(:updated) do
updated = double('updated')
allow(updated).to receive(:[]).and_return(Hash.new)
allow(updated).to receive(:_attributes_).and_return(Hash.new)
updated
end
before(:each) { allow(subject).to receive(:valid?).and_return(true) }
it "sends an update message to the implementing class" do
expect(subject.class).to receive(:update).with(anything, subject).and_return(updated)
subject.update
end
it "returns true" do
expect(subject.class).to receive(:update).with(anything, subject).and_return(updated)
expect(subject.update).to eql(true)
end
end
context "when the object is invalid" do
before(:each) { allow(subject).to receive(:valid?).and_return(false) }
it "raises an InvalidResource error" do
expect {
subject.update
}.to raise_error(Ridley::Errors::InvalidResource)
end
end
end
describe "#chef_id" do
it "returns the value of the chef_id attribute" do
subject.class.attribute(:name)
allow(subject.class).to receive(:chef_id) { :name }
subject.mass_assign(name: "reset")
expect(subject.chef_id).to eql("reset")
end
end
describe "#reload" do
let(:updated_subject) { double('updated_subject', _attributes_: { fake_attribute: "some_value" }) }
before(:each) do
subject.class.attribute(:fake_attribute)
allow(subject.class).to receive(:find).with(client, subject).and_return(updated_subject)
end
it "returns itself" do
expect(subject.reload).to eql(subject)
end
it "sets the attributes of self to include those of the reloaded object" do
subject.reload
expect(subject.get_attribute(:fake_attribute)).to eql("some_value")
end
end
end
ridley-5.1.1/spec/support/spec_helpers.rb 0000644 0000041 0000041 00000000561 13123557300 020506 0 ustar www-data www-data module Ridley
module SpecHelpers
def app_root_path
Pathname.new(File.expand_path('../../../', __FILE__))
end
def clean_tmp_path
FileUtils.rm_rf(tmp_path)
FileUtils.mkdir_p(tmp_path)
end
def fixtures_path
app_root_path.join('spec/fixtures')
end
def tmp_path
app_root_path.join('spec/tmp')
end
end
end
ridley-5.1.1/spec/support/each_matcher.rb 0000644 0000041 0000041 00000000404 13123557300 020431 0 ustar www-data www-data RSpec::Matchers.define :each do |check|
match do |actual|
actual.each_with_index do |index, o|
@object = o
expect(index).to check
end
end
failure_message do |actual|
"at[#{@object}] #{check.failure_message_for_should}"
end
end
ridley-5.1.1/spec/acceptance/ 0000755 0000041 0000041 00000000000 13123557300 016055 5 ustar www-data www-data ridley-5.1.1/spec/acceptance/client_resource_spec.rb 0000644 0000041 0000041 00000005454 13123557300 022611 0 ustar www-data www-data require 'spec_helper'
describe "Client API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
describe "finding a client" do
context "when the server has a client of the given name" do
before { chef_client("reset", admin: false) }
it "returns a ClientObject" do
expect(connection.client.find("reset")).to be_a(Ridley::ClientObject)
end
end
context "when the server does not have the client" do
it "returns a nil value" do
expect(connection.client.find("not_there")).to be_nil
end
end
end
describe "creating a client" do
it "returns a Ridley::ClientObject" do
expect(connection.client.create(name: "reset")).to be_a(Ridley::ClientObject)
end
it "adds a client to the chef server" do
old = connection.client.all.length
connection.client.create(name: "reset")
expect(connection.client.all.size).to eq(old + 1)
end
it "has a value for #private_key" do
expect(connection.client.create(name: "reset").private_key).not_to be_nil
end
end
describe "deleting a client" do
before { chef_client("reset", admin: false) }
it "returns a Ridley::ClientObject object" do
expect(connection.client.delete("reset")).to be_a(Ridley::ClientObject)
end
it "removes the client from the server" do
connection.client.delete("reset")
expect(connection.client.find("reset")).to be_nil
end
end
describe "deleting all clients" do
before(:each) do
chef_client("reset", admin: false)
chef_client("jwinsor", admin: false)
end
it "returns an array of Ridley::ClientObject objects" do
expect(connection.client.delete_all).to each be_a(Ridley::ClientObject)
end
it "deletes all clients from the remote" do
connection.client.delete_all
expect(connection.client.all.size).to eq(0)
end
end
describe "listing all clients" do
before(:each) do
chef_client("reset", admin: false)
chef_client("jwinsor", admin: false)
end
it "returns an array of Ridley::ClientObject objects" do
expect(connection.client.all).to each be_a(Ridley::ClientObject)
end
it "returns all of the clients on the server" do
expect(connection.client.all.size).to eq(4)
end
end
describe "regenerating a client's private key" do
before { chef_client("reset", admin: false) }
it "returns a Ridley::ClientObject object with a value for #private_key" do
expect(connection.client.regenerate_key("reset").private_key).to match(/^-----BEGIN RSA PRIVATE KEY-----/)
end
end
end
ridley-5.1.1/spec/acceptance/environment_resource_spec.rb 0000644 0000041 0000041 00000007556 13123557300 023704 0 ustar www-data www-data require 'spec_helper'
describe "Environment API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
describe "finding an environment" do
before { chef_environment("ridley-test-env") }
it "returns a valid Ridley::EnvironmentObject object" do
expect(connection.environment.find("ridley-test-env")).to be_a(Ridley::EnvironmentObject)
end
end
describe "creating an environment" do
it "returns a valid Ridley::EnvironmentObject object" do
obj = connection.environment.create(name: "ridley-test-env", description: "a testing env for ridley")
expect(obj).to be_a(Ridley::EnvironmentObject)
end
it "adds an environment to the chef server" do
old = connection.environment.all.length
connection.environment.create(name: "ridley")
expect(connection.environment.all.size).to eq(old + 1)
end
end
describe "deleting an environment" do
before { chef_environment("ridley-env") }
it "returns a Ridley::EnvironmentObject object" do
expect(connection.environment.delete("ridley-env")).to be_a(Ridley::EnvironmentObject)
end
it "removes the environment from the server" do
connection.environment.delete("ridley-env")
expect(connection.environment.find("ridley-env")).to be_nil
end
it "raises Ridley::Errors::HTTPMethodNotAllowed when attempting to delete the '_default' environment" do
expect {
connection.environment.delete("_default")
}.to raise_error(Ridley::Errors::HTTPMethodNotAllowed)
end
end
describe "deleting all environments" do
before do
chef_environment("ridley-one")
chef_environment("ridley-two")
end
it "returns an array of Ridley::EnvironmentObject objects" do
expect(connection.environment.delete_all).to each be_a(Ridley::EnvironmentObject)
end
it "deletes all environments but '_default' from the remote" do
connection.environment.delete_all
expect(connection.environment.all.size).to eq(1)
end
end
describe "listing all environments" do
it "should return an array of Ridley::EnvironmentObject objects" do
expect(connection.environment.all).to each be_a(Ridley::EnvironmentObject)
end
end
describe "updating an environment" do
before { chef_environment("ridley-env") }
let(:target ) { connection.environment.find("ridley-env") }
it "saves a new #description" do
target.description = description = "ridley testing environment"
connection.environment.update(target)
expect(target.reload.description).to eql(description)
end
it "saves a new set of 'default_attributes'" do
target.default_attributes = default_attributes = {
"attribute_one" => "val_one",
"nested" => {
"other" => "val"
}
}
connection.environment.update(target)
obj = connection.environment.find(target)
expect(obj.default_attributes).to eql(default_attributes)
end
it "saves a new set of 'override_attributes'" do
target.override_attributes = override_attributes = {
"attribute_one" => "val_one",
"nested" => {
"other" => "val"
}
}
connection.environment.update(target)
obj = connection.environment.find(target)
expect(obj.override_attributes).to eql(override_attributes)
end
it "saves a new set of 'cookbook_versions'" do
target.cookbook_versions = cookbook_versions = {
"nginx" => "1.2.0",
"tomcat" => "1.3.0"
}
connection.environment.update(target)
obj = connection.environment.find(target)
expect(obj.cookbook_versions).to eql(cookbook_versions)
end
end
end
ridley-5.1.1/spec/acceptance/search_resource_spec.rb 0000644 0000041 0000041 00000001562 13123557300 022574 0 ustar www-data www-data require 'spec_helper'
describe "Search API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
describe "listing indexes" do
it "returns an array of indexes" do
indexes = connection.search_indexes
expect(indexes).to include("role")
expect(indexes).to include("node")
expect(indexes).to include("client")
expect(indexes).to include("environment")
end
end
describe "searching an index that doesn't exist" do
it "it raises a Ridley::Errors::HTTPNotFound error" do
expect {
connection.search(:notthere)
}.to raise_error(Ridley::Errors::HTTPNotFound)
end
end
end
ridley-5.1.1/spec/acceptance/user_resource_spec.rb 0000644 0000041 0000041 00000007755 13123557300 022317 0 ustar www-data www-data require 'spec_helper'
describe "User API operations", type: "wip" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:user_name) { "reset" }
let(:user_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: user_name, client_key: user_key) }
describe "finding a user" do
context "when the server has a user of the given name" do
before { chef_user("reset", admin: false) }
it "returns a UserObject" do
expect(connection.user.find("reset")).to be_a(Ridley::UserObject)
end
end
context "when the server does not have the user" do
it "returns a nil value" do
expect(connection.user.find("not_there")).to be_nil
end
end
end
describe "creating a user" do
it "returns a Ridley::UserObject" do
expect(connection.user.create(name: "reset")).to be_a(Ridley::UserObject)
end
it "adds a user to the chef server" do
old = connection.user.all.length
connection.user.create(name: "reset")
expect(connection.user.all.size).to eq(old + 1)
end
it "has a value for #private_key" do
expect(connection.user.create(name: "reset").private_key).not_to be_nil
end
end
describe "deleting a user" do
before { chef_user("reset", admin: false) }
it "returns a Ridley::UserObject object" do
expect(connection.user.delete("reset")).to be_a(Ridley::UserObject)
end
it "removes the user from the server" do
connection.user.delete("reset")
expect(connection.user.find("reset")).to be_nil
end
end
describe "deleting all users" do
before(:each) do
chef_user("reset", admin: false)
chef_user("jwinsor", admin: false)
end
it "returns an array of Ridley::UserObject objects" do
expect(connection.user.delete_all).to each be_a(Ridley::UserObject)
end
it "deletes all users from the remote" do
connection.user.delete_all
expect(connection.user.all.size).to eq(0)
end
end
describe "listing all users" do
before(:each) do
chef_user("reset", admin: false)
chef_user("jwinsor", admin: false)
end
it "returns an array of Ridley::UserObject objects" do
expect(connection.user.all).to each be_a(Ridley::UserObject)
end
it "returns all of the users on the server" do
expect(connection.user.all.size).to eq(3)
end
end
describe "regenerating a user's private key" do
before { chef_user("reset", admin: false) }
it "returns a Ridley::UserObject object with a value for #private_key" do
expect(connection.user.regenerate_key("reset").private_key).to match(/^-----BEGIN RSA PRIVATE KEY-----/)
end
end
describe "authenticating a user" do
before { chef_user('reset', password: 'swordfish') }
it "returns true when given valid username & password" do
expect(connection.user.authenticate('reset', 'swordfish')).to be_truthy
end
it "returns false when given valid username & invalid password" do
expect(connection.user.authenticate('reset', "not a swordfish")).to be_falsey
end
it "returns false when given invalid username & valid password" do
expect(connection.user.authenticate("someone-else", 'swordfish')).to be_falsey
end
it "works also on a User object level" do
expect(connection.user.find('reset').authenticate('swordfish')).to be_truthy
expect(connection.user.find('reset').authenticate('not a swordfish')).to be_falsey
end
end
describe "changing user's password" do
before { chef_user('reset', password: 'swordfish') }
subject { connection.user.find('reset') }
it "changes the password with which user can authenticate" do
expect(subject.authenticate('swordfish')).to be_truthy
expect(subject.authenticate('salmon')).to be_falsey
subject.password = 'salmon'
subject.save
expect(subject.authenticate('swordfish')).to be_falsey
expect(subject.authenticate('salmon')).to be_truthy
end
end
end
ridley-5.1.1/spec/acceptance/data_bag_item_resource_spec.rb 0000644 0000041 0000041 00000007736 13123557300 024100 0 ustar www-data www-data require 'spec_helper'
describe "DataBag API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
let(:data_bag) do
chef_data_bag("ridley-test")
connection.data_bag.find("ridley-test")
end
describe "listing data bag items" do
context "when the data bag has no items" do
it "returns an empty array" do
expect(data_bag.item.all.size).to eq(0)
end
end
context "when the data bag has items" do
before(:each) do
data_bag.item.create(id: "one")
data_bag.item.create(id: "two")
end
it "returns an array with each item" do
expect(data_bag.item.all.size).to eq(2)
end
end
end
describe "creating a data bag item" do
it "adds a data bag item to the collection of data bag items" do
data_bag.item.create(id: "appconfig", host: "host.local", port: 80, admin: false, servers: ["one"])
expect(data_bag.item.all.size).to eq(1)
end
context "when an 'id' field is missing" do
it "raises an Ridley::Errors::InvalidResource error" do
expect {
data_bag.item.create(name: "jamie")
}.to raise_error(Ridley::Errors::InvalidResource)
end
end
end
describe "retrieving a data bag item" do
it "returns the desired item in the data bag" do
attributes = {
"id" => "appconfig",
"host" => "host.local",
"port" => 80,
"admin" => false,
"servers" => [
"one"
]
}
data_bag.item.create(attributes)
expect(data_bag.item.find("appconfig").to_hash).to eql(attributes)
end
end
describe "deleting a data bag item" do
let(:attributes) do
{
"id" => "appconfig",
"host" => "host.local"
}
end
before { data_bag.item.create(attributes) }
it "returns the deleted data bag item" do
dbi = data_bag.item.delete(attributes["id"])
expect(dbi).to be_a(Ridley::DataBagItemObject)
expect(dbi.attributes).to eql(attributes)
end
it "deletes the data bag item from the server" do
data_bag.item.delete(attributes["id"])
expect(data_bag.item.find(attributes["id"])).to be_nil
end
end
describe "deleting all data bag items in a data bag" do
before do
data_bag.item.create(id: "one")
data_bag.item.create(id: "two")
end
it "returns the array of deleted data bag items" do
expect(data_bag.item.delete_all).to each be_a(Ridley::DataBagItemObject)
end
it "removes all data bag items from the data bag" do
data_bag.item.delete_all
expect(data_bag.item.all.size).to eq(0)
end
end
describe "updating a data bag item" do
before { data_bag.item.create(id: "one") }
it "returns the updated data bag item" do
dbi = data_bag.item.update(id: "one", name: "brooke")
expect(dbi[:name]).to eql("brooke")
end
end
describe "saving a data bag item" do
context "when the data bag item exists" do
let(:dbi) { data_bag.item.create(id: "ridley-test") }
it "returns true if successful" do
dbi[:name] = "brooke"
expect(dbi.save).to be_truthy
end
it "creates a new data bag item on the remote" do
dbi[:name] = "brooke"
dbi.save
expect(data_bag.item.all.size).to eq(1)
end
end
context "when the data bag item does not exist" do
it "returns true if successful" do
dbi = data_bag.item.new
dbi.attributes = { id: "not-there", name: "brooke" }
expect(dbi.save).to be_truthy
end
it "creates a new data bag item on the remote" do
dbi = data_bag.item.new
dbi.attributes = { id: "not-there", name: "brooke" }
dbi.save
expect(data_bag.item.all.size).to eq(1)
end
end
end
end
ridley-5.1.1/spec/acceptance/cookbook_resource_spec.rb 0000644 0000041 0000041 00000004607 13123557300 023140 0 ustar www-data www-data require 'spec_helper'
describe "Client API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
subject { connection.cookbook }
describe "downloading a cookbook" do
before { subject.upload(fixtures_path.join('example_cookbook')) }
let(:name) { "example_cookbook" }
let(:version) { "0.1.0" }
let(:destination) { tmp_path.join("example_cookbook-0.1.0") }
context "when the cookbook of the name/version is found" do
before { subject.download(name, version, destination) }
it "downloads the cookbook to the destination" do
expect(File.exist?(destination.join("metadata.json"))).to be_truthy
end
end
end
describe "uploading a cookbook" do
let(:path) { fixtures_path.join("example_cookbook") }
it "uploads the entire contents of the cookbook in the given path, applying chefignore" do
subject.upload(path)
cookbook = subject.find("example_cookbook", "0.1.0")
expect(cookbook.attributes.size).to eq(1)
expect(cookbook.definitions.size).to eq(1)
expect(cookbook.files.size).to eq(2)
expect(cookbook.libraries.size).to eq(1)
expect(cookbook.providers.size).to eq(1)
expect(cookbook.recipes.size).to eq(1)
expect(cookbook.resources.size).to eq(1)
expect(cookbook.templates.size).to eq(1)
expect(cookbook.root_files.size).to eq(1)
end
it "does not contain a raw metadata.rb but does contain a compiled metadata.json" do
subject.upload(path)
cookbook = subject.find("example_cookbook", "0.1.0")
expect(cookbook.root_files.any? { |f| f[:name] == "metadata.json" }).to be_truthy
expect(cookbook.root_files.any? { |f| f[:name] == "metadata.rb" }).to be_falsey
end
end
describe "listing cookbooks" do
before do
chef_cookbook("ruby", "1.0.0")
chef_cookbook("ruby", "2.0.0")
chef_cookbook("elixir", "3.0.0")
chef_cookbook("elixir", "3.0.1")
end
it "returns all of the cookbooks on the server" do
all_cookbooks = subject.all
expect(all_cookbooks.size).to eq(2)
expect(all_cookbooks["ruby"].size).to eq(2)
expect(all_cookbooks["elixir"].size).to eq(2)
end
end
end
ridley-5.1.1/spec/acceptance/node_resource_spec.rb 0000644 0000041 0000041 00000007707 13123557300 022263 0 ustar www-data www-data require 'spec_helper'
describe "Node API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
describe "finding a node" do
let(:node_name) { "ridley.localhost" }
before { chef_node(node_name) }
it "returns a Ridley::NodeObject" do
expect(connection.node.find(node_name)).to be_a(Ridley::NodeObject)
end
end
describe "creating a node" do
let(:node_name) { "ridley.localhost" }
it "returns a new Ridley::NodeObject object" do
expect(connection.node.create(name: node_name)).to be_a(Ridley::NodeObject)
end
it "adds a new node to the server" do
connection.node.create(name: node_name)
expect(connection.node.all.size).to eq(1)
end
end
describe "deleting a node" do
let(:node_name) { "ridley.localhost" }
before { chef_node(node_name) }
it "returns a Ridley::NodeObject" do
expect(connection.node.delete(node_name)).to be_a(Ridley::NodeObject)
end
it "removes the node from the server" do
connection.node.delete(node_name)
expect(connection.node.find(node_name)).to be_nil
end
end
describe "deleting all nodes" do
before do
chef_node("ridley.localhost")
chef_node("motherbrain.localhost")
end
it "deletes all nodes from the remote server" do
connection.node.delete_all
expect(connection.node.all.size).to eq(0)
end
end
describe "listing all nodes" do
before do
chef_node("ridley.localhost")
chef_node("motherbrain.localhost")
end
it "returns an array of Ridley::NodeObject" do
obj = connection.node.all
expect(obj).to each be_a(Ridley::NodeObject)
expect(obj.size).to eq(2)
end
end
describe "updating a node" do
let(:node_name) { "ridley.localhost" }
before { chef_node(node_name) }
let(:target) { connection.node.find(node_name) }
it "returns the updated node" do
expect(connection.node.update(target)).to eql(target)
end
it "saves a new set of 'normal' attributes" do
target.normal = normal = {
"attribute_one" => "value_one",
"nested" => {
"other" => "val"
}
}
connection.node.update(target)
obj = connection.node.find(target)
expect(obj.normal).to eql(normal)
end
it "saves a new set of 'default' attributes" do
target.default = defaults = {
"attribute_one" => "val_one",
"nested" => {
"other" => "val"
}
}
connection.node.update(target)
obj = connection.node.find(target)
expect(obj.default).to eql(defaults)
end
it "saves a new set of 'automatic' attributes" do
target.automatic = automatics = {
"attribute_one" => "val_one",
"nested" => {
"other" => "val"
}
}
connection.node.update(target)
obj = connection.node.find(target)
expect(obj.automatic).to eql(automatics)
end
it "saves a new set of 'override' attributes" do
target.override = overrides = {
"attribute_one" => "val_one",
"nested" => {
"other" => "val"
}
}
connection.node.update(target)
obj = connection.node.find(target)
expect(obj.override).to eql(overrides)
end
it "places a node in a new 'chef_environment'" do
target.chef_environment = environment = "ridley"
connection.node.update(target)
obj = connection.node.find(target)
expect(obj.chef_environment).to eql(environment)
end
it "saves a new 'run_list' for the node" do
target.run_list = run_list = ["recipe[one]", "recipe[two]"]
connection.node.update(target)
obj = connection.node.find(target)
expect(obj.run_list).to eql(run_list)
end
end
end
ridley-5.1.1/spec/acceptance/role_resource_spec.rb 0000644 0000041 0000041 00000007134 13123557300 022271 0 ustar www-data www-data require 'spec_helper'
describe "Role API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
describe "finding a role" do
let(:role_name) { "ridley-role" }
before { chef_role(role_name) }
it "returns a Ridley::RoleObject" do
expect(connection.role.find(role_name)).to be_a(Ridley::RoleObject)
end
end
describe "creating a role" do
let(:role_name) { "ridley-role" }
it "returns a new Ridley::RoleObject" do
expect(connection.role.create(name: role_name)).to be_a(Ridley::RoleObject)
end
it "adds a new role to the server" do
connection.role.create(name: role_name)
expect(connection.role.all.size).to eq(1)
end
end
describe "deleting a role" do
let(:role_name) { "ridley-role" }
before { chef_role(role_name) }
it "returns the deleted Ridley::RoleObject resource" do
expect(connection.role.delete(role_name)).to be_a(Ridley::RoleObject)
end
it "removes the role from the server" do
connection.role.delete(role_name)
expect(connection.role.find(role_name)).to be_nil
end
end
describe "deleting all roles" do
before do
chef_role("role_one")
chef_role("role_two")
end
it "deletes all nodes from the remote server" do
connection.role.delete_all
expect(connection.role.all.size).to eq(0)
end
end
describe "listing all roles" do
before do
chef_role("role_one")
chef_role("role_two")
end
it "should return an array of Ridley::RoleObject" do
obj = connection.role.all
expect(obj.size).to eq(2)
expect(obj).to each be_a(Ridley::RoleObject)
end
end
describe "updating a role" do
let(:role_name) { "ridley-role" }
before { chef_role(role_name) }
let(:target) { connection.role.find(role_name) }
it "returns an updated Ridley::RoleObject object" do
expect(connection.role.update(target)).to eql(target)
end
it "saves a new run_list" do
target.run_list = run_list = ["recipe[one]", "recipe[two]"]
connection.role.update(target)
obj = connection.role.find(target)
expect(obj.run_list).to eql(run_list)
end
it "saves a new env_run_lists" do
target.env_run_lists = env_run_lists = {
"production" => ["recipe[one]"],
"development" => ["recipe[two]"]
}
connection.role.update(target)
obj = connection.role.find(target)
expect(obj.env_run_lists).to eql(env_run_lists)
end
it "saves a new description" do
target.description = description = "a new description!"
connection.role.update(target)
obj = connection.role.find(target)
expect(obj.description).to eql(description)
end
it "saves a new default_attributes" do
target.default_attributes = defaults = {
"attribute_one" => "value_one",
"nested" => {
"other" => false
}
}
connection.role.update(target)
obj = connection.role.find(target)
expect(obj.default_attributes).to eql(defaults)
end
it "saves a new override_attributes" do
target.override_attributes = overrides = {
"attribute_two" => "value_two",
"nested" => {
"other" => false
}
}
connection.role.update(target)
obj = connection.role.find(target)
expect(obj.override_attributes).to eql(overrides)
end
end
end
ridley-5.1.1/spec/acceptance/data_bag_resource_spec.rb 0000644 0000041 0000041 00000002154 13123557300 023047 0 ustar www-data www-data require 'spec_helper'
describe "DataBag API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
describe "listing data bags" do
context "when no data bags exist" do
it "returns an empty array" do
expect(connection.data_bag.all.size).to eq(0)
end
end
context "when the server has data bags" do
before do
chef_data_bag("ridley-one")
chef_data_bag("ridley-two")
end
it "returns an array of data bags" do
expect(connection.data_bag.all).to each be_a(Ridley::DataBagObject)
end
it "returns all of the data bags on the server" do
expect(connection.data_bag.all.size).to eq(2)
end
end
end
describe "creating a data bag" do
it "returns a Ridley::DataBagObject" do
expect(connection.data_bag.create(name: "ridley-one")).to be_a(Ridley::DataBagObject)
end
end
end
ridley-5.1.1/spec/acceptance/sandbox_resource_spec.rb 0000644 0000041 0000041 00000002032 13123557300 022756 0 ustar www-data www-data require 'spec_helper'
describe "Sandbox API operations", type: "acceptance" do
let(:server_url) { Ridley::RSpec::ChefServer.server_url }
let(:client_name) { "reset" }
let(:client_key) { fixtures_path.join('reset.pem').to_s }
let(:connection) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
let(:checksums) do
[
Ridley::SandboxUploader.checksum(File.open(fixtures_path.join("recipe_one.rb"))),
Ridley::SandboxUploader.checksum(File.open(fixtures_path.join("recipe_two.rb")))
]
end
describe "creating a new sandbox" do
it "returns an instance of Ridley::SandboxObject" do
expect(connection.sandbox.create(checksums)).to be_a(Ridley::SandboxObject)
end
it "contains a value for sandbox_id" do
expect(connection.sandbox.create(checksums).sandbox_id).not_to be_nil
end
it "returns an instance with the same amount of checksums given to create" do
expect(connection.sandbox.create(checksums).checksums.size).to eq(2)
end
end
end
ridley-5.1.1/.travis.yml 0000644 0000041 0000041 00000001671 13123557300 015153 0 ustar www-data www-data sudo: false
language: ruby
addons:
apt:
packages:
- chef
- git
- graphviz
- libarchive12
- libarchive-dev
- libgecode-dev
sources:
- chef-stable-precise
cache:
- apt
- bundler
bundler_args: --without development
dist: precise
branches:
only:
- master
script: "bundle exec thor spec:all"
before_install:
- gem update --system
- gem install bundler
matrix:
include:
- rvm: 2.2.5
- rvm: 2.3.1
- rvm: ruby-head
# Test against master of berkshelf
# - rvm: 2.2.5
# gemfile: berkshelf/Gemfile
# before_install:
# - gem update --system
# - gem install bundler
# - git clone --depth 1 https://github.com/berkshelf/berkshelf
# - cd berkshelf
# - echo "gem 'ridley', :path => '..'" >> Gemfile
# install: bundle install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
# env:
# script: bundle exec thor spec:ci
ridley-5.1.1/lib/ 0000755 0000041 0000041 00000000000 13123557300 013603 5 ustar www-data www-data ridley-5.1.1/lib/ridley/ 0000755 0000041 0000041 00000000000 13123557300 015073 5 ustar www-data www-data ridley-5.1.1/lib/ridley/middleware/ 0000755 0000041 0000041 00000000000 13123557300 017210 5 ustar www-data www-data ridley-5.1.1/lib/ridley/middleware/follow_redirects.rb 0000644 0000041 0000041 00000011435 13123557300 023107 0 ustar www-data www-data require 'set'
module Ridley
module Middleware
# Borrowed and modified from:
# {https://github.com/lostisland/faraday_middleware/blob/master/lib/faraday_middleware/response/follow_redirects.rb}
#
# Public: Follow HTTP 301, 302, 303, and 307 redirects for GET, PATCH, POST,
# PUT, and DELETE requests.
#
# This middleware does not follow the HTTP specification for HTTP 302, by
# default, in that it follows the improper implementation used by most major
# web browsers which forces the redirected request to become a GET request
# regardless of the original request method.
#
# For HTTP 301, 302, and 303, the original request is transformed into a
# GET request to the response Location, by default. However, with standards
# compliance enabled, a 302 will instead act in accordance with the HTTP
# specification, which will replay the original request to the received
# Location, just as with a 307.
#
# For HTTP 307, the original request is replayed to the response Location,
# including original HTTP request method (GET, POST, PUT, DELETE, PATCH),
# original headers, and original body.
#
# This middleware currently only works with synchronous requests; in other
# words, it doesn't support parallelism.
class FollowRedirects < Faraday::Middleware
include Ridley::Logging
# HTTP methods for which 30x redirects can be followed
ALLOWED_METHODS = Set.new [:head, :options, :get, :post, :put, :patch, :delete]
# HTTP redirect status codes that this middleware implements
REDIRECT_CODES = Set.new [301, 302, 303, 307]
# Keys in env hash which will get cleared between requests
ENV_TO_CLEAR = Set.new [:status, :response, :response_headers]
# Default value for max redirects followed
FOLLOW_LIMIT = 3
# Public: Initialize the middleware.
#
# options - An options Hash (default: {}):
# limit - A Numeric redirect limit (default: 3)
# standards_compliant - A Boolean indicating whether to respect
# the HTTP spec when following 302
# (default: false)
# cookie - Use either an array of strings
# (e.g. ['cookie1', 'cookie2']) to choose kept cookies
# or :all to keep all cookies.
def initialize(app, options = {})
super(app)
@options = options
@replay_request_codes = Set.new [307]
@replay_request_codes << 302 if standards_compliant?
end
def call(env)
perform_with_redirection(env, follow_limit)
end
private
def perform_with_redirection(env, follows)
request_body = env[:body]
response = @app.call(env)
response.on_complete do |env|
if follow_redirect?(env, response)
log.debug { "==> request redirected to #{response['location']}" }
log.debug { "request env: #{env}" }
if follows.zero?
log.debug { "==> too many redirects" }
raise Ridley::Errors::RedirectLimitReached, response
end
env = update_env(env, request_body, response)
response = perform_with_redirection(env, follows - 1)
end
end
response
end
def update_env(env, request_body, response)
env[:url] += response['location']
if @options[:cookies]
cookies = keep_cookies(env)
env[:request_headers][:cookies] = cookies unless cookies.nil?
end
env[:body] = request_body
ENV_TO_CLEAR.each {|key| env.delete key }
env
end
def follow_redirect?(env, response)
ALLOWED_METHODS.include? env[:method] and
REDIRECT_CODES.include? response.status
end
def follow_limit
@options.fetch(:limit, FOLLOW_LIMIT)
end
def keep_cookies(env)
cookies = @options.fetch(:cookies, [])
response_cookies = env[:response_headers][:cookies]
cookies == :all ? response_cookies : selected_request_cookies(response_cookies)
end
def selected_request_cookies(cookies)
selected_cookies(cookies)[0...-1]
end
def selected_cookies(cookies)
"".tap do |cookie_string|
@options[:cookies].each do |cookie|
string = /#{cookie}=?[^;]*/.match(cookies)[0] + ';'
cookie_string << string
end
end
end
def standards_compliant?
@options.fetch(:standards_compliant, false)
end
end
end
end
Faraday::Response.register_middleware follow_redirects: Ridley::Middleware::FollowRedirects
ridley-5.1.1/lib/ridley/middleware/chef_auth.rb 0000644 0000041 0000041 00000005473 13123557300 021474 0 ustar www-data www-data require 'mixlib/authentication/signedheaderauth'
module Ridley
module Middleware
class ChefAuth < Faraday::Middleware
class << self
include Mixlib::Authentication
# Generate authentication headers for a request to a Chef Server
#
# @param [String] client_name
# @param [String] client_key
# the path OR actual client key
#
# @option options [String] :host
#
# @see {#signing_object} for options
def authentication_headers(client_name, client_key, options = {})
contents = File.exists?(client_key) ? File.read(client_key) : client_key.to_s
rsa_key = OpenSSL::PKey::RSA.new(contents)
headers = signing_object(client_name, options).sign(rsa_key).merge(host: options[:host])
headers.inject({}) { |memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo }
end
# Create a signing object for a Request to a Chef Server
#
# @param [String] client_name
#
# @option options [String] :http_method
# @option options [String] :path
# @option options [String] :body
# @option options [Time] :timestamp
#
# @return [SigningObject]
def signing_object(client_name, options = {})
options = options.reverse_merge(
body: String.new,
timestamp: Time.now.utc.iso8601
)
options[:user_id] = client_name
options[:proto_version] = "1.0"
SignedHeaderAuth.signing_object(options)
end
end
include Ridley::Logging
attr_reader :client_name
attr_reader :client_key
def initialize(app, client_name, client_key)
super(app)
@client_name = client_name
@client_key = client_key
end
def call(env)
signing_options = {
http_method: env[:method],
host: "#{env[:url].host}:#{env[:url].port}",
path: env[:url].path,
body: env[:body] || ''
}
authentication_headers = self.class.authentication_headers(client_name, client_key, signing_options)
env[:request_headers] = default_headers.merge(env[:request_headers]).merge(authentication_headers)
env[:request_headers] = env[:request_headers].merge('Content-Length' => env[:body].bytesize.to_s) if env[:body]
log.debug { "==> performing authenticated Chef request as '#{client_name}'"}
log.debug { "request env: #{env}"}
@app.call(env)
end
private
def default_headers
{
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Chef-Version' => Ridley::CHEF_VERSION
}
end
end
end
end
Faraday::Request.register_middleware chef_auth: Ridley::Middleware::ChefAuth
ridley-5.1.1/lib/ridley/middleware/parse_json.rb 0000644 0000041 0000041 00000005474 13123557300 021712 0 ustar www-data www-data module Ridley
module Middleware
class ParseJson < Faraday::Response::Middleware
include Ridley::Logging
JSON_TYPE = 'application/json'.freeze
BRACKETS = [
"[",
"{"
].freeze
WHITESPACE = [
" ",
"\n",
"\r",
"\t"
].freeze
class << self
include Ridley::Logging
# Takes a string containing JSON and converts it to a Ruby hash
# symbols for keys
#
# @param [String] body
#
# @return [Hash]
def parse(body)
result = JSON.parse(body)
result.is_a?(Hash) ? Hashie::Mash.new(result) : result
end
# Extracts the type of the response from the response headers
# of a Faraday request env. 'text/html' will be returned if no
# content-type is specified in the response
#
# @example
# env = {
# :response_headers => {
# 'content-type' => 'text/html; charset=utf-8'
# }
# ...
# }
#
# ParseJson.response_type(env) => 'application/json'
#
# @param [Hash] env
# a Faraday request env
#
# @return [String]
def response_type(env)
if env[:response_headers][CONTENT_TYPE].nil?
log.debug { "response did not specify a content type" }
return "text/html"
end
env[:response_headers][CONTENT_TYPE].split(';', 2).first
end
# Determines if the response of the given Faraday request env
# contains JSON
#
# @param [Hash] env
# a Faraday request env
#
# @return [Boolean]
def json_response?(env)
response_type(env) == JSON_TYPE && looks_like_json?(env)
end
# Examines the body of a request env and returns true if it appears
# to contain JSON or false if it does not
#
# @param [Hash] env
# a Faraday request env
# @return [Boolean]
def looks_like_json?(env)
return false unless env[:body].present?
BRACKETS.include?(first_char(env[:body]))
end
private
def first_char(body)
idx = -1
begin
char = body[idx += 1]
char = char.chr if char
end while char && WHITESPACE.include?(char)
char
end
end
def on_complete(env)
if self.class.json_response?(env)
log.debug { "==> parsing Chef response body as JSON" }
env[:body] = self.class.parse(env[:body])
else
log.debug { "==> Chef response did not contain a JSON body" }
end
end
end
end
end
Faraday::Response.register_middleware parse_json: Ridley::Middleware::ParseJson
ridley-5.1.1/lib/ridley/middleware/chef_response.rb 0000644 0000041 0000041 00000001505 13123557300 022361 0 ustar www-data www-data module Ridley
module Middleware
class ChefResponse < Faraday::Response::Middleware
class << self
# Determines if a response from the Chef server was successful
#
# @param [Hash] env
# a faraday request env
#
# @return [Boolean]
def success?(env)
(200..210).to_a.index(env[:status].to_i) ? true : false
end
end
include Ridley::Logging
def on_complete(env)
log.debug { "==> handling Chef response" }
log.debug { "request env: #{env}" }
unless self.class.success?(env)
log.debug { "** error encounted in Chef response" }
raise Errors::HTTPError.fabricate(env)
end
end
end
end
end
Faraday::Response.register_middleware chef_response: Ridley::Middleware::ChefResponse
ridley-5.1.1/lib/ridley/mixin/ 0000755 0000041 0000041 00000000000 13123557300 016217 5 ustar www-data www-data ridley-5.1.1/lib/ridley/mixin/checksum.rb 0000644 0000041 0000041 00000000476 13123557300 020355 0 ustar www-data www-data module Ridley::Mixin
# Inspired by and dependency-free replacement for
# {https://github.com/opscode/chef/blob/11.4.0/lib/chef/mixin/checksum.rb}
module Checksum
# @param [String] file
#
# @return [String]
def checksum(file)
Ridley::Chef::Digester.checksum_for_file(file)
end
end
end
ridley-5.1.1/lib/ridley/mixin/params_validate.rb 0000644 0000041 0000041 00000020020 13123557300 021672 0 ustar www-data www-data require 'ridley/errors'
module Ridley::Mixin
# Borrowed and modified from: {https://raw.github.com/opscode/chef/11.4.0/lib/chef/mixin/params_validate.rb}
#
# Copyright:: Copyright (c) 2008 Opscode, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module ParamsValidate
include Ridley::Errors
# Takes a hash of options, along with a map to validate them. Returns the original
# options hash, plus any changes that might have been made (through things like setting
# default values in the validation map)
#
# For example:
#
# validate({ :one => "neat" }, { :one => { :kind_of => String }})
#
# Would raise an exception if the value of :one above is not a kind_of? string. Valid
# map options are:
#
# :default:: Sets the default value for this parameter.
# :callbacks:: Takes a hash of Procs, which should return true if the argument is valid.
# The key will be inserted into the error message if the Proc does not return true:
# "Option #{key}'s value #{value} #{message}!"
# :kind_of:: Ensure that the value is a kind_of?(Whatever). If passed an array, it will ensure
# that the value is one of those types.
# :respond_to:: Ensure that the value has a given method. Takes one method name or an array of
# method names.
# :required:: Raise an exception if this parameter is missing. Valid values are true or false,
# by default, options are not required.
# :regex:: Match the value of the paramater against a regular expression.
# :equal_to:: Match the value of the paramater with ==. An array means it can be equal to any
# of the values.
def validate(opts, map)
#--
# validate works by taking the keys in the validation map, assuming it's a hash, and
# looking for _pv_:symbol as methods. Assuming it find them, it calls the right
# one.
#++
raise ArgumentError, "Options must be a hash" unless opts.kind_of?(Hash)
raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
map.each do |key, validation|
unless key.kind_of?(Symbol) || key.kind_of?(String)
raise ArgumentError, "Validation map keys must be symbols or strings!"
end
case validation
when true
_pv_required(opts, key)
when false
true
when Hash
validation.each do |check, carg|
check_method = "_pv_#{check.to_s}"
if self.respond_to?(check_method, true)
self.send(check_method, opts, key, carg)
else
raise ArgumentError, "Validation map has unknown check: #{check}"
end
end
end
end
opts
end
def set_or_return(symbol, arg, validation)
iv_symbol = "@#{symbol.to_s}".to_sym
map = {
symbol => validation
}
if arg == nil && self.instance_variable_defined?(iv_symbol) == true
self.instance_variable_get(iv_symbol)
else
opts = validate({ symbol => arg }, { symbol => validation })
self.instance_variable_set(iv_symbol, opts[symbol])
end
end
private
# Return the value of a parameter, or nil if it doesn't exist.
def _pv_opts_lookup(opts, key)
if opts.has_key?(key.to_s)
opts[key.to_s]
elsif opts.has_key?(key.to_sym)
opts[key.to_sym]
else
nil
end
end
# Raise an exception if the parameter is not found.
def _pv_required(opts, key, is_required=true)
if is_required
if (opts.has_key?(key.to_s) && !opts[key.to_s].nil?) ||
(opts.has_key?(key.to_sym) && !opts[key.to_sym].nil?)
true
else
raise ValidationFailed, "Required argument #{key} is missing!"
end
end
end
def _pv_equal_to(opts, key, to_be)
value = _pv_opts_lookup(opts, key)
unless value.nil?
passes = false
Array(to_be).each do |tb|
passes = true if value == tb
end
unless passes
raise ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}."
end
end
end
# Raise an exception if the parameter is not a kind_of?(to_be)
def _pv_kind_of(opts, key, to_be)
value = _pv_opts_lookup(opts, key)
unless value.nil?
passes = false
Array(to_be).each do |tb|
passes = true if value.kind_of?(tb)
end
unless passes
raise ValidationFailed, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}."
end
end
end
# Raise an exception if the parameter does not respond to a given set of methods.
def _pv_respond_to(opts, key, method_name_list)
value = _pv_opts_lookup(opts, key)
unless value.nil?
Array(method_name_list).each do |method_name|
unless value.respond_to?(method_name)
raise ValidationFailed, "Option #{key} must have a #{method_name} method!"
end
end
end
end
# Assert that parameter returns false when passed a predicate method.
# For example, :cannot_be => :blank will raise a ValidationFailed
# error value.blank? returns a 'truthy' (not nil or false) value.
#
# Note, this will *PASS* if the object doesn't respond to the method.
# So, to make sure a value is not nil and not blank, you need to do
# both :cannot_be => :blank *and* :cannot_be => :nil (or :required => true)
def _pv_cannot_be(opts, key, predicate_method_base_name)
value = _pv_opts_lookup(opts, key)
predicate_method = (predicate_method_base_name.to_s + "?").to_sym
if value.respond_to?(predicate_method)
if value.send(predicate_method)
raise ValidationFailed, "Option #{key} cannot be #{predicate_method_base_name}"
end
end
end
# Assign a default value to a parameter.
def _pv_default(opts, key, default_value)
value = _pv_opts_lookup(opts, key)
if value == nil
opts[key] = default_value
end
end
# Check a parameter against a regular expression.
def _pv_regex(opts, key, regex)
value = _pv_opts_lookup(opts, key)
if value != nil
passes = false
[ regex ].flatten.each do |r|
if value != nil
if r.match(value.to_s)
passes = true
end
end
end
unless passes
raise ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}"
end
end
end
# Check a parameter against a hash of proc's.
def _pv_callbacks(opts, key, callbacks)
raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
value = _pv_opts_lookup(opts, key)
if value != nil
callbacks.each do |message, zeproc|
if zeproc.call(value) != true
raise ValidationFailed, "Option #{key}'s value #{value} #{message}!"
end
end
end
end
# Allow a parameter to default to @name
def _pv_name_attribute(opts, key, is_name_attribute=true)
if is_name_attribute
if opts[key] == nil
opts[key] = self.instance_variable_get("@name")
end
end
end
end
end
ridley-5.1.1/lib/ridley/mixin/from_file.rb 0000644 0000041 0000041 00000003661 13123557300 020514 0 ustar www-data www-data module Ridley::Mixin
module FromFile
module ClassMethods
def from_file(filename, *args)
new(*args).from_file(filename)
end
def class_from_file(filename, *args)
new(*args).class_from_file(filename)
end
end
class << self
def included(base)
base.extend(ClassMethods)
end
end
# Loads the contents of a file within the context of the current object
#
# @param [#to_s] filename
# path to the file to load
#
# @raise [IOError] if the file does not exist or cannot be read
def from_file(filename)
filename = filename.to_s
ensure_presence!(filename)
with_error_handling(filename) do
self.instance_eval(IO.read(filename), filename, 1)
self
end
end
# Loads the contents of a file within the context of the current object's class
#
# @param [#to_s] filename
# path to the file to load
#
# @raise [IOError] if the file does not exist or cannot be read
def class_from_file(filename)
filename = filename.to_s
ensure_presence!(filename)
with_error_handling(filename) do
self.class_eval(IO.read(filename), filename, 1)
self
end
end
private
# Ensure the given filename and path is readable
#
# @param [String] filename
#
# @raise [IOError]
# if the target file does not exist or is not readable
def ensure_presence!(filename)
unless File.exists?(filename) && File.readable?(filename)
raise IOError, "Could not open or read: '#{filename}'"
end
end
# Execute the given block, handling any exceptions that occur
#
# @param [String] filename
#
# @raise [Ridley::Errors::FromFileParserError]
# if any exceptions if raised
def with_error_handling(filename)
yield
rescue => e
raise Ridley::Errors::FromFileParserError.new(filename, e)
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/ 0000755 0000041 0000041 00000000000 13123557300 017511 5 ustar www-data www-data ridley-5.1.1/lib/ridley/chef_objects/data_bag_item_obect.rb 0000644 0000041 0000041 00000010067 13123557300 023756 0 ustar www-data www-data require 'yaml'
module Ridley
class DataBagItemObject < ChefObject
set_chef_id "id"
set_assignment_mode :carefree
# @return [Ridley::DataBagObject]
attr_reader :data_bag
attribute :id,
type: String,
required: true
alias_method :attributes=, :mass_assign
alias_method :attributes, :_attributes_
# @param [Ridley::DataBagItemResource] resource
# @param [Ridley::DataBagObject] data_bag
# @param [#to_hash] new_attrs
def initialize(resource, data_bag, new_attrs = {})
super(resource, new_attrs)
@data_bag = data_bag
end
# Creates a resource on the target remote or updates one if the resource
# already exists.
#
# @raise [Errors::InvalidResource]
# if the resource does not pass validations
#
# @return [Boolean]
# true if successful and false for failure
def save
raise Errors::InvalidResource.new(self.errors) unless valid?
mass_assign(resource.create(data_bag, self)._attributes_)
true
rescue Errors::HTTPConflict
self.update
true
end
# Decrypts this data bag item.
#
# @return [Hash] decrypted attributes
def decrypt
decrypted_hash = Hash[_attributes_.map { |key, value| [key, key == "id" ? value : decrypt_value(value)] }]
mass_assign(decrypted_hash)
end
# Decrypts an individual value stored inside the data bag item.
#
# @example
# data_bag_item.decrypt_value("Xk0E8lV9r4BhZzcg4wal0X4w9ZexN3azxMjZ9r1MCZc=")
# => {test: {database: {username: "test"}}}
#
# @param [String] an encrypted String value
#
# @return [Hash] a decrypted attribute value
def decrypt_value(value)
case format_version_of(value)
when 0
decrypt_v0_value(value)
when 1
decrypt_v1_value(value)
else
raise NotImplementedError, "Currently decrypting only version 0 & 1 databags are supported"
end
end
# Reload the attributes of the instantiated resource
#
# @return [Object]
def reload
mass_assign(resource.find(data_bag, self)._attributes_)
self
end
# Updates the instantiated resource on the target remote with any changes made
# to self
#
# @raise [Errors::InvalidResource]
# if the resource does not pass validations
#
# @return [Boolean]
def update
raise Errors::InvalidResource.new(self.errors) unless valid?
mass_assign(resource.update(data_bag, self)._attributes_)
true
end
# @param [#to_hash] hash
#
# @return [Object]
def from_hash(hash)
hash = Hashie::Mash.new(hash.to_hash)
mass_assign(hash.has_key?(:raw_data) ? hash[:raw_data] : hash)
self
end
private
# Shamelessly lifted from https://github.com/opscode/chef/blob/2c0040c95bb942d13ad8c47498df56be43e9a82e/lib/chef/encrypted_data_bag_item.rb#L209-L215
def format_version_of(encrypted_value)
if encrypted_value.respond_to?(:key?)
encrypted_value["version"]
else
0
end
end
def decrypt_v0_value(value)
if encrypted_data_bag_secret.nil?
raise Errors::EncryptedDataBagSecretNotSet
end
decoded_value = Base64.decode64(value)
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
cipher.decrypt
cipher.pkcs5_keyivgen(encrypted_data_bag_secret)
decrypted_value = cipher.update(decoded_value) + cipher.final
YAML.load(decrypted_value)
end
def decrypt_v1_value(attrs)
if encrypted_data_bag_secret.nil?
raise Errors::EncryptedDataBagSecretNotSet
end
cipher = OpenSSL::Cipher::Cipher.new(attrs[:cipher])
cipher.decrypt
cipher.key = Digest::SHA256.digest(encrypted_data_bag_secret)
cipher.iv = Base64.decode64(attrs[:iv])
decrypted_value = cipher.update(Base64.decode64(attrs[:encrypted_data])) + cipher.final
YAML.load(decrypted_value)["json_wrapper"]
end
def encrypted_data_bag_secret
resource.encrypted_data_bag_secret
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/data_bag_object.rb 0000644 0000041 0000041 00000001306 13123557300 023106 0 ustar www-data www-data module Ridley
class DataBagObject < ChefObject
set_chef_id "name"
attribute :name,
required: true
def item
DataBagItemProxy.new(self, resource.item_resource)
end
# @api private
class DataBagItemProxy
attr_reader :data_bag_object
attr_reader :item_resource
# @param [Ridley::DataBagObject] data_bag_object
# @param [Ridley::DataBagItemResource] item_resource
def initialize(data_bag_object, item_resource)
@data_bag_object = data_bag_object
@item_resource = item_resource
end
def method_missing(fun, *args, &block)
@item_resource.send(fun, data_bag_object, *args, &block)
end
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/client_object.rb 0000644 0000041 0000041 00000002421 13123557300 022641 0 ustar www-data www-data module Ridley
class ClientObject < Ridley::ChefObject
set_chef_id "name"
set_chef_type "client"
set_chef_json_class "Chef::ApiClient"
attribute :name,
type: String,
required: true
attribute :admin,
type: Buff::Boolean,
required: true,
default: false
attribute :validator,
type: Buff::Boolean,
required: true,
default: false
attribute :certificate,
type: String
attribute :public_key,
type: String
attribute :private_key,
type: [ String, Buff::Boolean ],
default: false
attribute :orgname,
type: String
# Regenerates the private key of the instantiated client object. The new
# private key will be set to the value of the 'private_key' accessor
# of the instantiated client object.
#
# @return [Boolean]
# true for success and false for failure
def regenerate_key
self.private_key = true
self.save
end
# Override to_json to reflect to massage the returned attributes based on the type
# of connection. Only OHC/OPC requires the json_class attribute is not present.
def to_json
if resource.connection.hosted?
to_hash.except(:json_class).to_json
else
super
end
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/environment_object.rb 0000644 0000041 0000041 00000006777 13123557300 023751 0 ustar www-data www-data module Ridley
class EnvironmentObject < Ridley::ChefObject
set_chef_id "name"
set_chef_type "environment"
set_chef_json_class "Chef::Environment"
attribute :name,
required: true
attribute :description,
default: String.new
attribute :default_attributes,
default: Hashie::Mash.new
attribute :override_attributes,
default: Hashie::Mash.new
attribute :cookbook_versions,
default: Hashie::Mash.new
# Set an environment level default attribute given the dotted path representation of
# the Chef attribute and value
#
# @example setting and saving an environment level default attribute
#
# obj = environment.find("production")
# obj.set_default_attribute("my_app.billing.enabled", false)
# obj.save
#
# @param [String] key
# @param [Object] value
#
# @return [Hashie::Mash]
def set_default_attribute(key, value)
attr_hash = Hashie::Mash.from_dotted_path(key, value)
self.default_attributes = self.default_attributes.deep_merge(attr_hash)
end
# Set an environment level override attribute given the dotted path representation of
# the Chef attribute and value
#
# @example setting and saving an environment level override attribute
#
# obj = environment.find("production")
# obj.set_override_attribute("my_app.billing.enabled", false)
# obj.save
#
# @param [String] key
# @param [Object] value
#
# @return [Hashie::Mash]
def set_override_attribute(key, value)
attr_hash = Hashie::Mash.from_dotted_path(key, value)
self.override_attributes = self.override_attributes.deep_merge(attr_hash)
end
# Removes a environment default attribute given its dotted path
# representation. Returns the default attributes of the environment.
#
# @param [String] key
# the dotted path to an attribute
#
# @return [Hashie::Mash]
def unset_default_attribute(key)
unset_attribute(key, :default)
end
alias :delete_default_attribute :unset_default_attribute
# Removes a environment override attribute given its dotted path
# representation. Returns the override attributes of the environment.
#
# @param [String] key
# the dotted path to an attribute
#
# @return [Hashie::Mash]
def unset_override_attribute(key)
unset_attribute(key, :override)
end
alias :delete_override_attribute :unset_override_attribute
private
# Deletes an attribute at the given precedence using its dotted-path key.
#
# @param [String] key
# the dotted path to an attribute
# @param [Symbol] precedence
# the precedence level to delete the attribute from
#
# @return [Hashie::Mash]
def unset_attribute(key, precedence)
keys = key.split(".")
leaf_key = keys.pop
attributes_to_change = case precedence
when :default
self.default_attributes
when :override
self.override_attributes
end
leaf_attributes = keys.inject(attributes_to_change) do |attributes, key|
if attributes[key] && attributes[key].kind_of?(Hashie::Mash)
attributes = attributes[key]
else
return attributes_to_change
end
end
leaf_attributes.delete(leaf_key)
return attributes_to_change
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/role_object.rb 0000644 0000041 0000041 00000003240 13123557300 022324 0 ustar www-data www-data module Ridley
class RoleObject < Ridley::ChefObject
set_chef_id "name"
set_chef_type "role"
set_chef_json_class "Chef::Role"
attribute :name,
required: true
attribute :description,
default: String.new
attribute :default_attributes,
default: Hashie::Mash.new
attribute :override_attributes,
default: Hashie::Mash.new
attribute :run_list,
default: Array.new
attribute :env_run_lists,
default: Hash.new
# Set a role level override attribute given the dotted path representation of the Chef
# attribute and value
#
# @example setting and saving a node level override attribute
#
# obj = node.role("why_god_why")
# obj.set_override_attribute("my_app.billing.enabled", false)
# obj.save
#
# @param [String] key
# @param [Object] value
#
# @return [Hashie::Mash]
def set_override_attribute(key, value)
attr_hash = Hashie::Mash.from_dotted_path(key, value)
self.override_attributes = self.override_attributes.deep_merge(attr_hash)
end
# Set a role level default attribute given the dotted path representation of the Chef
# attribute and value
#
# @example setting and saving a node level default attribute
#
# obj = node.role("why_god_why")
# obj.set_default_attribute("my_app.billing.enabled", false)
# obj.save
#
# @param [String] key
# @param [Object] value
#
# @return [Hashie::Mash]
def set_default_attribute(key, value)
attr_hash = Hashie::Mash.from_dotted_path(key, value)
self.default_attributes = self.default_attributes.deep_merge(attr_hash)
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/cookbook_object.rb 0000644 0000041 0000041 00000011055 13123557300 023174 0 ustar www-data www-data module Ridley
class CookbookObject < Ridley::ChefObject
include Ridley::Logging
FILE_TYPES = [
:resources,
:providers,
:recipes,
:definitions,
:libraries,
:attributes,
:files,
:templates,
:root_files
].freeze
set_chef_id "cookbook_name"
set_chef_type "cookbook"
set_chef_json_class "Chef::Cookbook"
attribute :name,
required: true
attribute :attributes,
type: Array,
default: Array.new
attribute :cookbook_name,
type: String
attribute :definitions,
type: Array,
default: Array.new
attribute :files,
type: Array,
default: Array.new
attribute :libraries,
type: Array,
default: Array.new
attribute :metadata,
type: Hashie::Mash
attribute :providers,
type: Array,
default: Array.new
attribute :recipes,
type: Array,
default: Array.new
attribute :resources,
type: Array,
default: Array.new
attribute :root_files,
type: Array,
default: Array.new
attribute :templates,
type: Array,
default: Array.new
attribute :version,
type: String
attribute :frozen?,
type: Buff::Boolean
# Download the entire cookbook
#
# @param [String] destination (Dir.mktmpdir)
# the place to download the cookbook too. If no value is provided the cookbook
# will be downloaded to a temporary location
#
# @return [String]
# the path to the directory the cookbook was downloaded to
def download(destination = Dir.mktmpdir)
destination = File.expand_path(destination)
log.debug { "downloading cookbook: '#{name}'" }
FILE_TYPES.each do |filetype|
next unless manifest.has_key?(filetype)
manifest[filetype].each do |file|
file_destination = File.join(destination, file[:path].gsub('/', File::SEPARATOR))
FileUtils.mkdir_p(File.dirname(file_destination))
download_file(filetype, file[:path], file_destination)
end
end
destination
end
# Download a single file from a cookbook
#
# @param [#to_sym] filetype
# the type of file to download. These are broken up into the following types in Chef:
# - attribute
# - definition
# - file
# - library
# - provider
# - recipe
# - resource
# - root_file
# - template
# these types are where the files are stored in your cookbook's structure. For example, a
# recipe would be stored in the recipes directory while a root_file is stored at the root
# of your cookbook
# @param [String] path
# path of the file to download
# @param [String] destination
# where to download the file to
#
# @return [nil]
def download_file(filetype, path, destination)
file_list = case filetype.to_sym
when :attribute, :attributes; attributes
when :definition, :definitions; definitions
when :file, :files; files
when :library, :libraries; libraries
when :provider, :providers; providers
when :recipe, :recipes; recipes
when :resource, :resources; resources
when :root_file, :root_files; root_files
when :template, :templates; templates
else
raise Errors::UnknownCookbookFileType.new(filetype)
end
file = file_list.find { |f| f[:path] == path }
return nil if file.nil?
destination = File.expand_path(destination)
log.debug { "downloading '#{filetype}' file: #{file} to: '#{destination}'" }
resource.connection.stream(file[:url], destination)
end
# A hash containing keys for all of the different cookbook filetypes with values
# representing each file of that type this cookbook contains
#
# @example
# {
# root_files: [
# {
# :name => "afile.rb",
# :path => "files/ubuntu-9.10/afile.rb",
# :checksum => "2222",
# :specificity => "ubuntu-9.10"
# },
# ],
# templates: [ manifest_record1, ... ],
# ...
# }
#
# @return [Hash]
def manifest
{}.tap do |manifest|
FILE_TYPES.each do |filetype|
manifest[filetype] = get_attribute(filetype)
end
end
end
# Reload the attributes of the instantiated resource
#
# @return [Ridley::CookbookObject]
def reload
mass_assign(resource.find(self, self.version)._attributes_)
self
end
def to_s
"#{name}: #{manifest}"
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/user_object.rb 0000644 0000041 0000041 00000002455 13123557300 022350 0 ustar www-data www-data module Ridley
class UserObject < Ridley::ChefObject
set_chef_id "name"
set_chef_type "user"
set_chef_json_class "Chef::User"
attribute :name,
type: String,
required: true
attribute :admin,
type: Buff::Boolean,
required: true,
default: false
attribute :certificate,
type: String
attribute :public_key,
type: String
attribute :private_key,
type: [ String, Buff::Boolean ],
default: false
attribute :password,
type: String
attribute :orgname,
type: String
# Regenerates the private key of the instantiated user object. The new
# private key will be set to the value of the 'private_key' accessor
# of the instantiated user object.
#
# @return [Boolean]
# true for success and false for failure
def regenerate_key
self.private_key = true
self.save
end
def authenticate(password)
@resource.authenticate(self.chef_id, password)
end
# Override to_json to reflect to massage the returned attributes based on the type
# of connection. Only OHC/OPC requires the json_class attribute is not present.
def to_json
if resource.connection.hosted?
to_hash.except(:json_class).to_json
else
super
end
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/sandbox_object.rb 0000644 0000041 0000041 00000003031 13123557300 023017 0 ustar www-data www-data module Ridley
class SandboxObject < ChefObject
set_chef_id "sandbox_id"
attribute :sandbox_id,
type: String
attribute :uri,
type: String
attribute :checksums,
type: Hash
attribute :is_completed,
type: Buff::Boolean,
default: false
# Return information about the given checksum
#
# @example
# sandbox.checksum("e5a0f6b48d0712382295ff30bec1f9cc") => {
# needs_upload: true,
# url: "https://s3.amazonaws.com/opscode-platform-production-data/organization"
# }
#
# @param [#to_sym] chk_id
# checksum to retrieve information about
#
# @return [Hash]
# a hash containing the checksum information
def checksum(chk_id)
checksums[chk_id.to_sym]
end
# Concurrently upload all of this sandboxes files into the checksum containers of the sandbox
#
# @param [Hash] checksums
# a hash of file checksums and file paths
#
# @example
# sandbox.upload(
# "e5a0f6b48d0712382295ff30bec1f9cc" => "/Users/reset/code/rbenv-cookbook/recipes/default.rb",
# "de6532a7fbe717d52020dc9f3ae47dbe" => "/Users/reset/code/rbenv-cookbook/recipes/ohai_plugin.rb"
# )
def upload(checksums)
resource.upload(self, checksums)
end
# Notify the Chef Server that uploading to this sandbox has completed
#
# @raise [Ridley::Errors::SandboxCommitError]
def commit
response = resource.commit(self)
set_attribute(:is_completed, response[:is_completed])
end
end
end
ridley-5.1.1/lib/ridley/chef_objects/node_object.rb 0000644 0000041 0000041 00000012201 13123557300 022305 0 ustar www-data www-data module Ridley
class NodeObject < Ridley::ChefObject
set_chef_id "name"
set_chef_type "node"
set_chef_json_class "Chef::Node"
attribute :name,
required: true
attribute :chef_environment,
default: "_default"
attribute :automatic,
default: Hashie::Mash.new
attribute :normal,
default: Hashie::Mash.new
attribute :default,
default: Hashie::Mash.new
attribute :override,
default: Hashie::Mash.new
attribute :run_list,
default: Array.new
alias_method :normal_attributes, :normal
alias_method :automatic_attributes, :automatic
alias_method :default_attributes, :default
alias_method :override_attributes, :override
# A merged hash containing a deep merge of all of the attributes respecting the node attribute
# precedence level.
#
# @return [hashie::Mash]
def chef_attributes
default.merge(normal.merge(override.merge(automatic)))
end
# Set a node level normal attribute given the dotted path representation of the Chef
# attribute and value.
#
# @note It is not possible to set any other attribute level on a node and have it persist after
# a Chef Run. This is because all other attribute levels are truncated at the start of a Chef Run.
#
# @example setting and saving a node level normal attribute
#
# obj = node.find("jwinsor-1")
# obj.set_chef_attribute("my_app.billing.enabled", false)
# obj.save
#
# @param [String] key
# dotted path to key to be unset
# @param [Object] value
#
# @return [Hashie::Mash]
def set_chef_attribute(key, value)
attr_hash = Hashie::Mash.from_dotted_path(key, value)
self.normal = self.normal.deep_merge(attr_hash)
end
# Unset a node level normal attribute given the dotted path representation of the Chef
# attribute and value.
#
# @example unsetting and saving a node level normal attribute
#
# obj = node.find("foonode")
# obj.unset_chef_attribute("my_app.service_one.service_state")
# obj.save
#
# @param [String] key
# dotted path to key to be unset
#
# @return [Hashie::Mash]
def unset_chef_attribute(key)
keys = key.split(".")
leaf_key = keys.pop
attributes = keys.inject(self.normal) do |attributes, key|
if attributes[key] && attributes[key].kind_of?(Hashie::Mash)
attributes = attributes[key]
else
return self.normal
end
end
attributes.delete(leaf_key)
return self.normal
end
# Returns the public hostname of the instantiated node. This hostname should be used for
# public communications to the node.
#
# @example
# node.public_hostname => "reset.riotgames.com"
#
# @return [String]
def public_hostname
self.cloud? ? self.automatic[:cloud][:public_hostname] || self.automatic[:fqdn] : self.automatic[:fqdn]
end
# Returns the public IPv4 address of the instantiated node. This ip address should be
# used for public communications to the node.
#
# @example
# node.public_ipv4 => "10.33.33.1"
#
# @return [String]
def public_ipv4
self.cloud? ? self.automatic[:cloud][:public_ipv4] || self.automatic[:ipaddress] : self.automatic[:ipaddress]
end
alias_method :public_ipaddress, :public_ipv4
# Returns the cloud provider of the instantiated node. If the node is not identified as
# a cloud node, then nil is returned.
#
# @example
# node_1.cloud_provider => "eucalyptus"
# node_2.cloud_provider => "ec2"
# node_3.cloud_provider => "rackspace"
# node_4.cloud_provider => nil
#
# @return [nil, String]
def cloud_provider
self.cloud? ? self.automatic[:cloud][:provider] : nil
end
# Returns true if the node is identified as a cloud node.
#
# @return [Boolean]
def cloud?
self.automatic.has_key?(:cloud)
end
# Returns true if the node is identified as a cloud node using the eucalyptus provider.
#
# @return [Boolean]
def eucalyptus?
self.cloud_provider == "eucalyptus"
end
# Returns true if the node is identified as a cloud node using the ec2 provider.
#
# @return [Boolean]
def ec2?
self.cloud_provider == "ec2"
end
# Returns true if the node is identified as a cloud node using the rackspace provider.
#
# @return [Boolean]
def rackspace?
self.cloud_provider == "rackspace"
end
# Merges the instaniated nodes data with the given data and updates
# the remote with the merged results
#
# @option options [Array] :run_list
# run list items to merge
# @option options [Hash] :attributes
# attributes of normal precedence to merge
#
# @return [Ridley::NodeObject]
def merge_data(options = {})
new_run_list = Array(options[:run_list])
new_attributes = options[:attributes]
unless new_run_list.empty?
self.run_list = self.run_list | new_run_list
end
unless new_attributes.nil?
self.normal = self.normal.deep_merge(new_attributes)
end
self
end
end
end
ridley-5.1.1/lib/ridley/connection.rb 0000644 0000041 0000041 00000011400 13123557300 017553 0 ustar www-data www-data require 'open-uri'
require 'retryable'
require 'tempfile'
require 'zlib'
require 'ridley/helpers'
module Ridley
class Connection < Faraday::Connection
include Celluloid
task_class TaskThread
VALID_OPTIONS = [
:retries,
:retry_interval,
:ssl,
:proxy
]
# @return [String]
attr_reader :organization
# @return [String]
attr_reader :client_key
# @return [String]
attr_reader :client_name
# @return [Integer]
# how many retries to attempt on HTTP requests
attr_reader :retries
# @return [Float]
# time to wait between retries
attr_reader :retry_interval
# @param [String] server_url
# @param [String] client_name
# @param [String] client_key
#
# @option options [Integer] :retries (5)
# retry requests on 5XX failures
# @option options [Float] :retry_interval (0.5)
# how often we should pause between retries
# @option options [Hash] :ssl
# * :verify (Boolean) [true] set to false to disable SSL verification
# @option options [URI, String, Hash] :proxy
# URI, String, or Hash of HTTP proxy options
def initialize(server_url, client_name, client_key, options = {})
options = options.reverse_merge(retries: 5, retry_interval: 0.5)
@client_name = client_name
@client_key = client_key
@retries = options.delete(:retries)
@retry_interval = options.delete(:retry_interval)
options[:builder] = Faraday::RackBuilder.new do |b|
b.request :retry,
max: @retries,
interval: @retry_interval,
exceptions: [
Ridley::Errors::HTTP5XXError,
Errno::ETIMEDOUT,
Faraday::Error::TimeoutError
]
b.request :chef_auth, client_name, client_key
b.response :parse_json
b.response :chef_response
b.adapter :httpclient
end
uri_hash = Ridley::Helpers.options_slice(Addressable::URI.parse(server_url).to_hash, :scheme, :host, :port)
unless uri_hash[:port]
uri_hash[:port] = (uri_hash[:scheme] == "https" ? 443 : 80)
end
if org_match = server_url.match(/.*\/organizations\/(.*)/)
@organization = org_match[1]
end
unless @organization.nil?
uri_hash[:path] = "/organizations/#{@organization}"
end
super(Addressable::URI.new(uri_hash), options)
@headers[:user_agent] = "Ridley v#{Ridley::VERSION}"
end
# @return [Symbol]
def api_type
organization.nil? ? :foss : :hosted
end
# @return [Boolean]
def hosted?
api_type == :hosted
end
# @return [Boolean]
def foss?
api_type == :foss
end
# Override Faraday::Connection#run_request to catch exceptions from {Ridley::Middleware} that
# we expect. Caught exceptions are re-raised with Celluloid#abort so we don't crash the connection.
def run_request(*args)
super
rescue Errors::HTTPError => ex
abort ex
rescue Faraday::Error::ConnectionFailed => ex
abort Errors::ConnectionFailed.new(ex)
rescue Faraday::Error::TimeoutError => ex
abort Errors::TimeoutError.new(ex)
rescue Faraday::Error::ClientError => ex
abort Errors::ClientError.new(ex)
end
def server_url
self.url_prefix.to_s
end
# Stream the response body of a remote URL to a file on the local file system
#
# @param [String] target
# a URL to stream the response body from
# @param [String] destination
# a location on disk to stream the content of the response body to
#
# @return [Boolean] true when the destination file exists
def stream(target, destination)
FileUtils.mkdir_p(File.dirname(destination))
target = Addressable::URI.parse(target)
headers = Middleware::ChefAuth.authentication_headers(
client_name,
client_key,
http_method: "GET",
host: target.host,
path: target.path
)
unless ssl[:verify]
headers.merge!(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
end
local = Tempfile.new('ridley-stream')
local.binmode
Retryable.retryable(tries: retries, on: OpenURI::HTTPError, sleep: retry_interval) do
open(target, 'rb', headers) do |remote|
body = remote.read
case remote.content_encoding
when ['gzip']
body = Zlib::GzipReader.new(StringIO.new(body), encoding: 'ASCII-8BIT').read
when ['deflate']
body = Zlib::Inflate.inflate(body)
end
local.write(body)
end
end
local.flush
FileUtils.cp(local.path, destination)
File.exists?(destination)
rescue OpenURI::HTTPError => ex
abort(ex)
ensure
local.close(true) unless local.nil?
end
end
end
ridley-5.1.1/lib/ridley/errors.rb 0000644 0000041 0000041 00000013333 13123557300 016737 0 ustar www-data www-data module Ridley
module Errors
class RidleyError < StandardError; end
class InternalError < RidleyError; end
class ArgumentError < InternalError; end
class ClientError < RidleyError; end
class ConnectionFailed < ClientError; end
class TimeoutError < ClientError; end
class ResourceNotFound < RidleyError; end
class ValidatorNotFound < RidleyError; end
class ValidationFailed < RidleyError; end
class InvalidResource < RidleyError
attr_reader :errors
def initialize(errors)
@errors = errors
end
def message
errors.values
end
alias_method :to_s, :message
end
class UnknownCookbookFileType < RidleyError
attr_reader :type
def initialize(type)
@type = type
end
def to_s
"filetype: '#{type}'"
end
end
class CookbookSyntaxError < RidleyError; end
class EncryptedDataBagSecretNotSet < RidleyError
def message
"no encrypted data bag secret was set for this Ridley connection"
end
end
class FromFileParserError < RidleyError
def initialize(filename, error)
super "Could not parse `#{filename}': #{error.message}"
# Populate the backtrace with the actual error though
set_backtrace(error.backtrace)
end
end
class MissingNameAttribute < RidleyError
def initialize(path)
@path = path
end
def to_s
out = "The metadata at '#{@path}' does not contain a 'name' "
out << "attribute. While Chef does not strictly enforce this "
out << "requirement, Ridley cannot continue without a valid metadata "
out << "'name' entry."
out
end
alias_method :message, :to_s
end
class ClientKeyFileNotFoundOrInvalid < RidleyError; end
class EncryptedDataBagSecretNotFound < RidleyError; end
# Exception thrown when the maximum amount of requests is exceeded.
class RedirectLimitReached < RidleyError
attr_reader :response
def initialize(response)
super "too many redirects; last one to: #{response['location']}"
@response = response
end
end
class FrozenCookbook < RidleyError; end
class SandboxCommitError < RidleyError; end
class PermissionDenied < RidleyError; end
class SandboxUploadError < RidleyError; end
class ChecksumMismatch < RidleyError; end
class HTTPError < RidleyError
class << self
def fabricate(env)
klass = lookup_error(env[:status].to_i)
klass.new(env)
end
def register_error(status)
error_map[status.to_i] = self
end
def lookup_error(status)
error_map.fetch(status.to_i)
rescue KeyError
HTTPUnknownStatus
end
def error_map
@@error_map ||= Hash.new
end
end
attr_reader :env
attr_reader :errors
attr_reader :message
alias_method :to_s, :message
def initialize(env)
@env = env
@errors = env[:body].is_a?(Hash) ? Array(env[:body][:error]) : []
if errors.empty?
@message = env[:body] || "no content body"
else
@message = "errors: "
@message << errors.collect { |e| "'#{e}'" }.join(', ')
end
end
end
class HTTPUnknownStatus < HTTPError
def initialize(env)
super(env)
@message = "status: #{env[:status]} is an unknown HTTP status code or not an error."
end
end
class HTTPUnknownMethod < HTTPError
attr_reader :method
def initialize(method)
@method = method
@message = "unknown http method: #{method}"
end
end
class HTTP3XXError < HTTPError; end
class HTTP4XXError < HTTPError; end
class HTTP5XXError < HTTPError; end
# 3XX
class HTTPMultipleChoices < HTTP3XXError; register_error(300); end
class HTTPMovedPermanently < HTTP3XXError; register_error(301); end
class HTTPFound < HTTP3XXError; register_error(302); end
class HTTPSeeOther < HTTP3XXError; register_error(303); end
class HTTPNotModified < HTTP3XXError; register_error(304); end
class HTTPUseProxy < HTTP3XXError; register_error(305); end
class HTTPTemporaryRedirect < HTTP3XXError; register_error(307); end
# 4XX
class HTTPBadRequest < HTTP4XXError; register_error(400); end
class HTTPUnauthorized < HTTP4XXError; register_error(401); end
class HTTPPaymentRequired < HTTP4XXError; register_error(402); end
class HTTPForbidden < HTTP4XXError; register_error(403); end
class HTTPNotFound < HTTP4XXError; register_error(404); end
class HTTPMethodNotAllowed < HTTP4XXError; register_error(405); end
class HTTPNotAcceptable < HTTP4XXError; register_error(406); end
class HTTPProxyAuthenticationRequired < HTTP4XXError; register_error(407); end
class HTTPRequestTimeout < HTTP4XXError; register_error(408); end
class HTTPConflict < HTTP4XXError; register_error(409); end
class HTTPGone < HTTP4XXError; register_error(410); end
class HTTPLengthRequired < HTTP4XXError; register_error(411); end
class HTTPPreconditionFailed < HTTP4XXError; register_error(412); end
class HTTPRequestEntityTooLarge < HTTP4XXError; register_error(413); end
class HTTPRequestURITooLong < HTTP4XXError; register_error(414); end
class HTTPUnsupportedMediaType < HTTP4XXError; register_error(415); end
# 5XX
class HTTPInternalServerError < HTTP5XXError; register_error(500); end
class HTTPNotImplemented < HTTP5XXError; register_error(501); end
class HTTPBadGateway < HTTP5XXError; register_error(502); end
class HTTPServiceUnavailable < HTTP5XXError; register_error(503); end
class HTTPGatewayTimeout < HTTP5XXError; register_error(504); end
end
end
ridley-5.1.1/lib/ridley/resources/ 0000755 0000041 0000041 00000000000 13123557300 017105 5 ustar www-data www-data ridley-5.1.1/lib/ridley/resources/search_resource.rb 0000644 0000041 0000041 00000014330 13123557300 022607 0 ustar www-data www-data module Ridley
class SearchResource < Ridley::Resource
class << self
# @param [String] query_string
#
# @option options [String] :sort
# a sort string such as 'name DESC'
# @option options [Integer] :rows
# how many rows to return
# @option options [Integer] :start
# the result number to start from
#
# @return [Hash]
def build_query(query_string, options = {})
{}.tap do |query_opts|
query_opts[:q] = query_string unless query_string.nil?
query_opts[:sort] = options[:sort] unless options[:sort].nil?
query_opts[:rows] = options[:rows] unless options[:rows].nil?
query_opts[:start] = options[:start] unless options[:start].nil?
end
end
# Builds and returns a query parameter string for the search API
#
# @param [String] query_string
#
# @option options [String] :sort
# a sort string such as 'name DESC'
# @option options [Integer] :rows
# how many rows to return
# @option options [Integer] :start
# the result number to start from
#
# @example
# build_param_string("*:*", rows: 5) #=> "?q=*:*&rows=5"
#
# @return [String]
def build_param_string(query_string, options = {})
query = build_query(query_string, options)
param = "?q=#{escape(query[:q])}"
param += "&sort=#{escape(query[:sort])}" if query[:sort]
param += "&start=#{escape(query[:start])}" if query[:start]
param += "&rows=#{escape(query[:rows])}" if query[:rows]
param
end
# @param [#to_s] index
#
# @return [String]
def query_uri(index)
"#{resource_path}/#{index}"
end
private
def escape(str)
str && URI.escape(str.to_s)
end
end
set_resource_path "search"
# Returns an array of possible search indexes to be search on
#
# @param [Ridley::Client] client
#
# @example
#
# Search.indexes(client) => [ :client, :environment, :node, :role ]
#
# @return [Array]
def indexes
request(:get, self.class.resource_path).collect { |name, _| name }
end
# Executes the built up query on the search's client
#
# @param [#to_sym, #to_s] index
# @param [#to_s] query_string
#
# @option options [String] :sort
# a sort string such as 'name DESC'
# @option options [Integer] :rows
# how many rows to return
# @option options [Integer] :start
# the result number to start from
#
# @example
# Search.new(client, :role)
# search.run =>
# {
# total: 1,
# start: 0,
# rows: [
# {
# name: "ridley-test-role",
# default_attributes: {},
# json_class: "Chef::Role",
# env_run_lists: {},
# run_list: [],
# description: "a test role for Ridley!",
# chef_type: "role",
# override_attributes: {}
# }
# ]
# }
#
# @return [Array, Hash]
def run(index, query_string, resources_registry, options = {})
query_uri = self.class.query_uri(index)
query = self.class.build_query(query_string, options)
handle_response(index, resources_registry, request(:get, query_uri, query))
end
# Perform a partial search on the Chef server
#
# @param [#to_sym, #to_s] index
# @param [#to_s] query_string
# @param [Array] attributes
# an array of strings in dotted hash notation representing the attributes to return
#
# @option options [String] :sort
# a sort string such as 'name DESC'
# @option options [Integer] :rows
# how many rows to return
# @option options [Integer] :start
# the result number to start from
#
# @return [Array, Hash]
def partial(index, query_string, attributes, resources_registry, options = {})
query_uri = self.class.query_uri(index)
param_string = self.class.build_param_string(query_string, options)
body = build_partial_body(index, attributes)
handle_partial(index, resources_registry, request(:post, "#{query_uri}#{param_string}", JSON.generate(body)))
end
private
def build_partial_body(index, attributes)
chef_id = chef_id_for_index(index)
Hash.new.tap do |body|
body[chef_id] = [ chef_id ] if chef_id
if index.to_sym == :node
body['cloud.public_hostname'] = [ 'cloud', 'public_hostname' ]
body['cloud.public_ip4v'] = [ 'cloud', 'public_ip4v' ]
body['cloud.provider'] = [ 'cloud', 'provider' ]
body['fqdn'] = [ 'fqdn' ]
body['ipaddress'] = [ 'ipaddress' ]
end
attributes.collect { |attr| body[attr] = attr.split('.') }
end
end
def chef_id_for_index(index)
chef_id = index.to_sym == :node ? Ridley::NodeObject.chef_id : nil
end
def handle_partial(index, registry, response)
chef_id = chef_id_for_index(index)
case index.to_sym
when :node
response[:rows].collect do |item|
attributes = Hashie::Mash.new
item[:data].each do |key, value|
next if key.to_s == chef_id.to_s
attributes.deep_merge!(Hash.from_dotted_path(key, value))
end
registry[:node_resource].new(name: item[:data][chef_id], automatic: attributes)
end
else
response[:rows]
end
end
def handle_response(index, registry, response)
case index.to_sym
when :node
response[:rows].collect { |row| NodeObject.new(registry[:node_resource], row) }
when :role
response[:rows].collect { |row| RoleObject.new(registry[:role_resource], row) }
when :client
response[:rows].collect { |row| ClientObject.new(registry[:client_resource], row) }
when :environment
response[:rows].collect { |row| EnvironmentObject.new(registry[:environment_resource], row) }
else
response[:rows]
end
end
end
end
ridley-5.1.1/lib/ridley/resources/cookbook_resource.rb 0000644 0000041 0000041 00000022341 13123557300 023151 0 ustar www-data www-data require 'ridley/helpers'
module Ridley
class CookbookResource < Ridley::Resource
task_class TaskThread
set_resource_path "cookbooks"
represented_by Ridley::CookbookObject
def initialize(connection_registry, client_name, client_key, options = {})
super(connection_registry)
@sandbox_resource = SandboxResource.new_link(connection_registry, client_name, client_key, options)
end
# List all of the cookbooks and their versions present on the remote
#
# @example return value
# {
# "ant" => [
# "0.10.1"
# ],
# "apache2" => [
# "1.4.0"
# ]
# }
#
# @return [Hash]
# a hash containing keys which represent cookbook names and values which contain
# an array of strings representing the available versions
def all
response = request(:get, self.class.resource_path, num_versions: "all")
{}.tap do |cookbooks|
response.each do |name, details|
cookbooks[name] = details["versions"].collect { |version| version["version"] }
end
end
end
# Delete a cookbook of the given name and version on the remote Chef server
#
# @param [String] name
# @param [String] version
#
# @option options [Boolean] purge (false)
#
# @return [Boolean]
def delete(name, version, options = {})
options = options.reverse_merge(purge: false)
url = "#{self.class.resource_path}/#{name}/#{version}"
url += "?purge=true" if options[:purge]
request(:delete, url)
true
rescue AbortError => ex
return nil if ex.cause.is_a?(Errors::HTTPNotFound)
abort(ex.cause)
end
# Delete all of the versions of a given cookbook on the remote Chef server
#
# @param [String] name
# name of the cookbook to delete
#
# @option options [Boolean] purge (false)
def delete_all(name, options = {})
versions(name).collect { |version| future(:delete, name, version, options) }.map(&:value)
end
# Download the entire cookbook
#
# @param [String] name
# @param [String] version
# @param [String] destination (Dir.mktmpdir)
# the place to download the cookbook too. If no value is provided the cookbook
# will be downloaded to a temporary location
#
# @raise [Errors::ResourceNotFound] if the target cookbook is not found
#
# @return [String]
# the path to the directory the cookbook was downloaded to
def download(name, version, destination = Dir.mktmpdir)
if cookbook = find(name, version)
cookbook.download(destination)
else
abort Errors::ResourceNotFound.new("cookbook #{name} (#{version}) was not found")
end
end
# @param [String, #chef_id] object
# @param [String] version
#
# @return [nil, CookbookResource]
def find(object, version)
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
new(request(:get, "#{self.class.resource_path}/#{chef_id}/#{version}"))
rescue AbortError => ex
return nil if ex.cause.is_a?(Errors::HTTPNotFound)
abort(ex.cause)
end
# Return the latest version of the given cookbook found on the remote Chef server
#
# @param [String] name
#
# @raise [Errors::ResourceNotFound] if the target cookbook has no versions
#
# @return [String, nil]
def latest_version(name)
ver = versions(name).collect do |version|
Semverse::Version.new(version)
end.sort.last
ver.nil? ? nil : ver.to_s
end
# Return the version of the given cookbook which best stasifies the given constraint
#
# @param [String] name
# name of the cookbook
# @param [String, Semverse::Constraint] constraint
# constraint to solve for
#
# @raise [Errors::ResourceNotFound] if the target cookbook has no versions
#
# @return [CookbookResource, nil]
# returns the cookbook resource for the best solution or nil if no solution exists
def satisfy(name, constraint)
version = Semverse::Constraint.satisfy_best(constraint, versions(name)).to_s
find(name, version)
rescue Semverse::NoSolutionError
nil
end
# Update or create a new Cookbook Version of the given name, version with the
# given manifest of files and checksums.
#
# @param [Ridley::Chef::Cookbook] cookbook
# the cookbook to save
#
# @option options [Boolean] :force
# Upload the Cookbook even if the version already exists and is frozen on
# the target Chef Server
# @option options [Boolean] :freeze
# Freeze the uploaded Cookbook on the Chef Server so that it cannot be
# overwritten
#
# @raise [Ridley::Errors::FrozenCookbook]
# if a cookbook of the same name and version already exists on the remote Chef server
# and is frozen. If the :force option is provided the given cookbook will be saved
# regardless.
#
# @return [Hash]
def update(cookbook, options = {})
options = options.reverse_merge(force: false, freeze: false)
cookbook.frozen = options[:freeze]
url = "cookbooks/#{cookbook.cookbook_name}/#{cookbook.version}"
url << "?force=true" if options[:force]
request(:put, url, cookbook.to_json)
rescue AbortError => ex
if ex.cause.is_a?(Errors::HTTPConflict)
abort Ridley::Errors::FrozenCookbook.new(ex)
end
abort(ex.cause)
end
alias_method :create, :update
# Uploads a cookbook to the remote Chef server from the contents of a filepath
#
# @param [String] path
# path to a cookbook on local disk
#
# @option options [Boolean] :force (false)
# Upload the Cookbook even if the version already exists and is frozen on
# the target Chef Server
# @option options [Boolean] :freeze (false)
# Freeze the uploaded Cookbook on the Chef Server so that it cannot be
# overwritten
# @option options [Boolean] :validate (true)
# Validate the contents of the cookbook before uploading
#
# @return [Hash]
def upload(path, options = {})
options = options.reverse_merge(validate: true, force: false, freeze: false)
cookbook = Ridley::Chef::Cookbook.from_path(path)
unless (existing = find(cookbook.cookbook_name, cookbook.version)).nil?
if existing.frozen? && options[:force] == false
msg = "The cookbook #{cookbook.cookbook_name} (#{cookbook.version}) already exists and is"
msg << " frozen on the Chef server. Use the 'force' option to override."
abort Ridley::Errors::FrozenCookbook.new(msg)
end
end
if options[:validate]
cookbook.validate
end
# Compile metadata on upload if it hasn't been compiled already
unless cookbook.compiled_metadata?
compiled_metadata = cookbook.compile_metadata
cookbook.reload
end
# Skip uploading the raw metadata (metadata.rb). The raw metadata is unecessary for the
# client, and this is required until compiled metadata (metadata.json) takes precedence over
# raw metadata in the Chef-Client.
#
# We can change back to including the raw metadata in the future after this has been fixed or
# just remove these comments. There is no circumstance that I can currently think of where
# raw metadata should ever be read by the client.
#
# - Jamie
#
# See the following tickets for more information:
# * https://tickets.opscode.com/browse/CHEF-4811
# * https://tickets.opscode.com/browse/CHEF-4810
cookbook.manifest[:root_files].reject! do |file|
File.basename(file[:name]).downcase == Ridley::Chef::Cookbook::Metadata::RAW_FILE_NAME
end
checksums = cookbook.checksums.dup
sandbox = sandbox_resource.create(checksums.keys.sort)
sandbox.upload(checksums)
sandbox.commit
update(cookbook, Ridley::Helpers.options_slice(options, :force, :freeze))
ensure
# Destroy the compiled metadata only if it was created
if compiled_metadata
# The garbage collector still has a reference to the file we'd
# like to delete. On *nix this isn't a big deal, but on Windows
# [ ruby 2.0.0p451 (2014-02-24) [i386-mingw32] ] open files
# cannot be deleted, so we're forced to garbage collect to
# ensure we can delete the file. This is CRITICAL to ensure that
# a stale metadata file isn't left on disk because next time we
# would use that file instead of recompiling.
GC.start
File.delete(compiled_metadata)
end
end
# Return a list of versions for the given cookbook present on the remote Chef server
#
# @param [String] name
#
# @example
# versions("nginx") => [ "1.0.0", "1.2.0" ]
#
# @raise [Errors::ResourceNotFound] if the target cookbook has no versions
#
# @return [Array]
def versions(name)
response = request(:get, "#{self.class.resource_path}/#{name}")
response[name]["versions"].collect do |cb_ver|
cb_ver["version"]
end
rescue AbortError => ex
if ex.cause.is_a?(Errors::HTTPNotFound)
abort Errors::ResourceNotFound.new(ex)
end
abort(ex.cause)
end
private
attr_reader :sandbox_resource
end
end
ridley-5.1.1/lib/ridley/resources/client_resource.rb 0000644 0000041 0000041 00000001767 13123557300 022632 0 ustar www-data www-data module Ridley
# @example listing all clients
# conn = Ridley.new(...)
# conn.client.all #=> [
# #,
# #
# ]
class ClientResource < Ridley::Resource
set_resource_path "clients"
represented_by Ridley::ClientObject
# Retrieves a client from the remote connection matching the given chef_id
# and regenerates its private key. An instance of the updated object will
# be returned and will have a value set for the 'private_key' accessor.
#
# @param [String, #chef_id] chef_client
#
# @raise [Errors::ResourceNotFound]
# if a client with the given chef_id is not found
#
# @return [Ridley::ClientObject]
def regenerate_key(chef_client)
unless chef_client = find(chef_client)
abort Errors::ResourceNotFound.new("client '#{chef_client}' not found")
end
chef_client.private_key = true
update(chef_client)
end
end
end
ridley-5.1.1/lib/ridley/resources/sandbox_resource.rb 0000644 0000041 0000041 00000006474 13123557300 023012 0 ustar www-data www-data module Ridley
class SandboxResource < Ridley::Resource
set_resource_path "sandboxes"
represented_by Ridley::SandboxObject
finalizer :finalize_callback
def initialize(connection_registry, client_name, client_key, options = {})
super(connection_registry)
options = options.reverse_merge(pool_size: 4)
@uploader = SandboxUploader.pool(size: options.delete(:pool_size), args: [ client_name, client_key, options ])
end
# Create a new Sandbox on the client's Chef Server. A Sandbox requires an
# array of file checksums which lets the Chef Server know what the signature
# of the contents to be uploaded will look like.
#
# @param [Ridley::Client] client
# @param [Array] checksums
# a hash of file checksums
#
# @example using the Ridley client to create a sandbox
# client.sandbox.create([
# "385ea5490c86570c7de71070bce9384a",
# "f6f73175e979bd90af6184ec277f760c",
# "2e03dd7e5b2e6c8eab1cf41ac61396d5"
# ])
#
# @return [Array]
def create(checksums = [])
sumhash = { checksums: Hash.new }.tap do |chks|
Array(checksums).each { |chk| chks[:checksums][chk] = nil }
end
new(request(:post, self.class.resource_path, JSON.fast_generate(sumhash)))
end
# @param [#chef_id] object
#
# @raise [Ridley::Errors::SandboxCommitError]
# @raise [Ridley::Errors::ResourceNotFound]
# @raise [Ridley::Errors::PermissionDenied]
#
# @return [Hash]
def commit(object)
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
request(:put, "#{self.class.resource_path}/#{chef_id}", JSON.fast_generate(is_completed: true))
rescue AbortError => ex
case ex.cause
when Ridley::Errors::HTTPBadRequest; abort Ridley::Errors::SandboxCommitError.new(ex.message)
when Ridley::Errors::HTTPNotFound; abort Ridley::Errors::ResourceNotFound.new(ex.message)
when Ridley::Errors::HTTPUnauthorized, Ridley::Errors::HTTPForbidden
abort Ridley::Errors::PermissionDenied.new(ex.message)
else; abort(ex.cause)
end
end
# Concurrently upload all of the files in the given sandbox
#
# @param [Ridley::SandboxObject] sandbox
# @param [Hash] checksums
# a hash of file checksums and file paths
#
# @example
# SandboxUploader.upload(sandbox,
# "e5a0f6b48d0712382295ff30bec1f9cc" => "/Users/reset/code/rbenv-cookbook/recipes/default.rb",
# "de6532a7fbe717d52020dc9f3ae47dbe" => "/Users/reset/code/rbenv-cookbook/recipes/ohai_plugin.rb"
# )
#
# @return [Array]
def upload(object, checksums)
checksums.collect do |chk_id, path|
uploader.future(:upload, object, chk_id, path)
end.map(&:value)
end
def update(*args)
abort RuntimeError.new("action not supported")
end
def all(*args)
abort RuntimeError.new("action not supported")
end
def find(*args)
abort RuntimeError.new("action not supported")
end
def delete(*args)
abort RuntimeError.new("action not supported")
end
def delete_all(*args)
abort RuntimeError.new("action not supported")
end
private
attr_reader :uploader
def finalize_callback
uploader.async.terminate if uploader
end
end
end
ridley-5.1.1/lib/ridley/resources/environment_resource.rb 0000644 0000041 0000041 00000002514 13123557300 023707 0 ustar www-data www-data module Ridley
class EnvironmentResource < Ridley::Resource
set_resource_path "environments"
represented_by Ridley::EnvironmentObject
# Used to return a hash of the cookbooks and cookbook versions (including all dependencies)
# that are required by the run_list array.
#
# @param [String] environment
# name of the environment to run against
# @param [Array] run_list
# an array of cookbooks to satisfy
#
# @raise [Errors::ResourceNotFound] if the given environment is not found
#
# @return [Hash]
def cookbook_versions(environment, run_list = [])
run_list = Array(run_list).flatten
chef_id = environment.respond_to?(:chef_id) ? environment.chef_id : environment
request(:post, "#{self.class.resource_path}/#{chef_id}/cookbook_versions", JSON.fast_generate(run_list: run_list))
rescue AbortError => ex
if ex.cause.is_a?(Errors::HTTPNotFound)
abort Errors::ResourceNotFound.new(ex)
end
abort(ex.cause)
end
# Delete all of the environments on the client. The '_default' environment
# will never be deleted.
#
# @return [Array]
def delete_all
envs = all.reject { |env| env.name.to_s == '_default' }
envs.collect { |resource| future(:delete, resource) }.map(&:value)
end
end
end
ridley-5.1.1/lib/ridley/resources/node_resource.rb 0000644 0000041 0000041 00000001707 13123557300 022273 0 ustar www-data www-data module Ridley
class NodeResource < Ridley::Resource
include Ridley::Logging
set_resource_path "nodes"
represented_by Ridley::NodeObject
# @param [Celluloid::Registry] connection_registry
def initialize(connection_registry, options = {})
super(connection_registry)
end
# Merges the given data with the the data of the target node on the remote
#
# @param [Ridley::NodeResource, String] target
# node or identifier of the node to merge
#
# @option options [Array] :run_list
# run list items to merge
# @option options [Hash] :attributes
# attributes of normal precedence to merge
#
# @raise [Errors::ResourceNotFound]
# if the target node is not found
#
# @return [Ridley::NodeObject]
def merge_data(target, options = {})
unless node = find(target)
abort Errors::ResourceNotFound.new
end
update(node.merge_data(options))
end
end
end
ridley-5.1.1/lib/ridley/resources/data_bag_resource.rb 0000644 0000041 0000041 00000002000 13123557300 023053 0 ustar www-data www-data module Ridley
class DataBagResource < Ridley::Resource
require_relative 'data_bag_item_resource'
set_resource_path "data"
represented_by Ridley::DataBagObject
attr_reader :item_resource
finalizer :finalize_callback
# @param [Celluloid::Registry] connection_registry
# @param [String] data_bag_secret
def initialize(connection_registry, data_bag_secret)
super(connection_registry)
@item_resource = DataBagItemResource.new_link(connection_registry, data_bag_secret)
end
# @param [String, #chef_id] object
#
# @return [nil, Ridley::DataBagResource]
def find(object)
chef_id = object.respond_to?(:chef_id) ? object.chef_id : object
request(:get, "#{self.class.resource_path}/#{chef_id}")
new(name: chef_id)
rescue AbortError => ex
return nil if ex.cause.is_a?(Errors::HTTPNotFound)
abort(ex.cause)
end
private
def finalize_callback
item_resource.async.terminate if item_resource
end
end
end
ridley-5.1.1/lib/ridley/resources/data_bag_item_resource.rb 0000644 0000041 0000041 00000005376 13123557300 024114 0 ustar www-data www-data module Ridley
class DataBagItemResource < Ridley::Resource
represented_by Ridley::DataBagItemObject
attr_reader :encrypted_data_bag_secret
# @param [Celluloid::Registry] connection_registry
# @param [String] encrypted_data_bag_secret
def initialize(connection_registry, encrypted_data_bag_secret)
super(connection_registry)
@encrypted_data_bag_secret = encrypted_data_bag_secret
end
# @param [Ridley::DataBagObject] data_bag
#
# @return [Array